From gregkh at linuxfoundation.org  Sun May  1 14:01:46 2016
From: gregkh at linuxfoundation.org (Greg Kroah-Hartman)
Date: Sun, 1 May 2016 14:01:46 -0700
Subject: [PATCH 08/12] nvmem: mtk-efuse: remove nvmem regmap dependency
In-Reply-To: <1461526096-29584-9-git-send-email-srinivas.kandagatla@linaro.org>
References: <1461526096-29584-1-git-send-email-srinivas.kandagatla@linaro.org>
 <1461526096-29584-9-git-send-email-srinivas.kandagatla@linaro.org>
Message-ID: <20160501210146.GA29070@kroah.com>

On Sun, Apr 24, 2016 at 08:28:12PM +0100, Srinivas Kandagatla wrote:
> This patch moves to nvmem support in the driver to use callback
> instead of regmap.
> 
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla at linaro.org>
> Acked-by: Andrew-CT Chen <andrew-ct.chen at mediatek.com>
> ---
>  drivers/nvmem/Kconfig     |  1 -
>  drivers/nvmem/mtk-efuse.c | 47 ++++++++++++++++++++++++++++++++---------------
>  2 files changed, 32 insertions(+), 16 deletions(-)

This patch didn't apply to my tree.  Can you fix it up and resend, and
also patch 11/12?

thanks,

greg k-h


From wsa at the-dreams.de  Mon May  2 00:32:54 2016
From: wsa at the-dreams.de (Wolfram Sang)
Date: Mon, 2 May 2016 09:32:54 +0200
Subject: [PATCH 02/12] eeprom: at24: remove nvmem regmap dependency
In-Reply-To: <1461526096-29584-3-git-send-email-srinivas.kandagatla@linaro.org>
References: <1461526096-29584-1-git-send-email-srinivas.kandagatla@linaro.org>
 <1461526096-29584-3-git-send-email-srinivas.kandagatla@linaro.org>
Message-ID: <20160502073254.GA2015@tetsubishi>

On Sun, Apr 24, 2016 at 08:28:06PM +0100, Srinivas Kandagatla wrote:
> This patch moves to nvmem support in the driver to use callback instead
> of regmap.
> 
> Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla at linaro.org>

Andrew, since you did the NVMEM implementation, could you have a look at
this? That would be awesome. Thanks!

> ---
>  drivers/misc/eeprom/Kconfig |   1 -
>  drivers/misc/eeprom/at24.c  | 103 ++++++++++----------------------------------
>  2 files changed, 22 insertions(+), 82 deletions(-)
> 
> diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> index cfc493c..2d70464 100644
> --- a/drivers/misc/eeprom/Kconfig
> +++ b/drivers/misc/eeprom/Kconfig
> @@ -3,7 +3,6 @@ menu "EEPROM support"
>  config EEPROM_AT24
>  	tristate "I2C EEPROMs / RAMs / ROMs from most vendors"
>  	depends on I2C && SYSFS
> -	select REGMAP
>  	select NVMEM
>  	help
>  	  Enable this driver to get read/write support to most I2C EEPROMs
> diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
> index 089d694..de550a6 100644
> --- a/drivers/misc/eeprom/at24.c
> +++ b/drivers/misc/eeprom/at24.c
> @@ -23,7 +23,6 @@
>  #include <linux/acpi.h>
>  #include <linux/i2c.h>
>  #include <linux/nvmem-provider.h>
> -#include <linux/regmap.h>
>  #include <linux/platform_data/at24.h>
>  
>  /*
> @@ -69,7 +68,6 @@ struct at24_data {
>  	unsigned write_max;
>  	unsigned num_addresses;
>  
> -	struct regmap_config regmap_config;
>  	struct nvmem_config nvmem_config;
>  	struct nvmem_device *nvmem;
>  
> @@ -252,10 +250,10 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
>  	return -ETIMEDOUT;
>  }
>  
> -static ssize_t at24_read(struct at24_data *at24,
> -		char *buf, loff_t off, size_t count)
> +static int at24_read(void *priv, unsigned int off, void *val, size_t count)
>  {
> -	ssize_t retval = 0;
> +	struct at24_data *at24 = priv;
> +	char *buf = val;
>  
>  	if (unlikely(!count))
>  		return count;
> @@ -267,23 +265,21 @@ static ssize_t at24_read(struct at24_data *at24,
>  	mutex_lock(&at24->lock);
>  
>  	while (count) {
> -		ssize_t	status;
> +		int	status;
>  
>  		status = at24_eeprom_read(at24, buf, off, count);
> -		if (status <= 0) {
> -			if (retval == 0)
> -				retval = status;
> -			break;
> +		if (status < 0) {
> +			mutex_unlock(&at24->lock);
> +			return status;
>  		}
>  		buf += status;
>  		off += status;
>  		count -= status;
> -		retval += status;
>  	}
>  
>  	mutex_unlock(&at24->lock);
>  
> -	return retval;
> +	return 0;
>  }
>  
>  /*
> @@ -372,13 +368,13 @@ static ssize_t at24_eeprom_write(struct at24_data *at24, const char *buf,
>  	return -ETIMEDOUT;
>  }
>  
> -static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
> -			  size_t count)
> +static int at24_write(void *priv, unsigned int off, void *val, size_t count)
>  {
> -	ssize_t retval = 0;
> +	struct at24_data *at24 = priv;
> +	char *buf = val;
>  
>  	if (unlikely(!count))
> -		return count;
> +		return -EINVAL;
>  
>  	/*
>  	 * Write data to chip, protecting against concurrent updates
> @@ -387,70 +383,23 @@ static ssize_t at24_write(struct at24_data *at24, const char *buf, loff_t off,
>  	mutex_lock(&at24->lock);
>  
>  	while (count) {
> -		ssize_t	status;
> +		int status;
>  
>  		status = at24_eeprom_write(at24, buf, off, count);
> -		if (status <= 0) {
> -			if (retval == 0)
> -				retval = status;
> -			break;
> +		if (status < 0) {
> +			mutex_unlock(&at24->lock);
> +			return status;
>  		}
>  		buf += status;
>  		off += status;
>  		count -= status;
> -		retval += status;
>  	}
>  
>  	mutex_unlock(&at24->lock);
>  
> -	return retval;
> -}
> -
> -/*-------------------------------------------------------------------------*/
> -
> -/*
> - * Provide a regmap interface, which is registered with the NVMEM
> - * framework
> -*/
> -static int at24_regmap_read(void *context, const void *reg, size_t reg_size,
> -			    void *val, size_t val_size)
> -{
> -	struct at24_data *at24 = context;
> -	off_t offset = *(u32 *)reg;
> -	int err;
> -
> -	err = at24_read(at24, val, offset, val_size);
> -	if (err)
> -		return err;
> -	return 0;
> -}
> -
> -static int at24_regmap_write(void *context, const void *data, size_t count)
> -{
> -	struct at24_data *at24 = context;
> -	const char *buf;
> -	u32 offset;
> -	size_t len;
> -	int err;
> -
> -	memcpy(&offset, data, sizeof(offset));
> -	buf = (const char *)data + sizeof(offset);
> -	len = count - sizeof(offset);
> -
> -	err = at24_write(at24, buf, offset, len);
> -	if (err)
> -		return err;
>  	return 0;
>  }
>  
> -static const struct regmap_bus at24_regmap_bus = {
> -	.read = at24_regmap_read,
> -	.write = at24_regmap_write,
> -	.reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
> -};
> -
> -/*-------------------------------------------------------------------------*/
> -
>  #ifdef CONFIG_OF
>  static void at24_get_ofdata(struct i2c_client *client,
>  		struct at24_platform_data *chip)
> @@ -482,7 +431,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
>  	struct at24_data *at24;
>  	int err;
>  	unsigned i, num_addresses;
> -	struct regmap *regmap;
>  
>  	if (client->dev.platform_data) {
>  		chip = *(struct at24_platform_data *)client->dev.platform_data;
> @@ -612,19 +560,6 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
>  		}
>  	}
>  
> -	at24->regmap_config.reg_bits = 32;
> -	at24->regmap_config.val_bits = 8;
> -	at24->regmap_config.reg_stride = 1;
> -	at24->regmap_config.max_register = chip.byte_len - 1;
> -
> -	regmap = devm_regmap_init(&client->dev, &at24_regmap_bus, at24,
> -				  &at24->regmap_config);
> -	if (IS_ERR(regmap)) {
> -		dev_err(&client->dev, "regmap init failed\n");
> -		err = PTR_ERR(regmap);
> -		goto err_clients;
> -	}
> -
>  	at24->nvmem_config.name = dev_name(&client->dev);
>  	at24->nvmem_config.dev = &client->dev;
>  	at24->nvmem_config.read_only = !writable;
> @@ -632,6 +567,12 @@ static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
>  	at24->nvmem_config.owner = THIS_MODULE;
>  	at24->nvmem_config.compat = true;
>  	at24->nvmem_config.base_dev = &client->dev;
> +	at24->nvmem_config.reg_read = at24_read;
> +	at24->nvmem_config.reg_write = at24_write;
> +	at24->nvmem_config.priv = at24;
> +	at24->nvmem_config.stride = 4;
> +	at24->nvmem_config.word_size = 1;
> +	at24->nvmem_config.size = chip.byte_len;
>  
>  	at24->nvmem = nvmem_register(&at24->nvmem_config);
>  
> -- 
> 2.5.0
> 
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160502/d9123fc5/attachment.sig>

From eballetbo at gmail.com  Mon May  2 02:13:31 2016
From: eballetbo at gmail.com (Enric Balletbo Serra)
Date: Mon, 2 May 2016 11:13:31 +0200
Subject: [PATCH 1/2] ASoC: rockchip: i2s: separate capture and playback
In-Reply-To: <20160430070049.GF14612@serenity.lan>
References: <1449657147-26959-1-git-send-email-john@metanate.com>
 <CAFqH_52C4JKno4uyt54UdWKAJKM4FPGRiQaQQ9_H-Mz1Cr+Hqg@mail.gmail.com>
 <20160430070049.GF14612@serenity.lan>
Message-ID: <CAFqH_51sSqaoUtadYux+A38wQ1y9T-GKU3_PEcgT9rp_19_b8g@mail.gmail.com>

Hi John,

Thanks for answer.

2016-04-30 9:00 GMT+02:00 John Keeping <john at keeping.me.uk>:
> Hi Enric,
>
> On Fri, Apr 29, 2016 at 04:59:27PM +0200, Enric Balletbo Serra wrote:
>> 2015-12-09 11:32 GMT+01:00 John Keeping <john at metanate.com>:
>> > If we only clear the tx/rx state when both are disabled it is not
>> > possible to start/stop one multiple times while the other is running.
>> > Since the two are independently controlled, treat them as such and
>> > remove the false dependency between capture and playback.
>> >
>> > Signed-off-by: John Keeping <john at metanate.com>
>> > ---
>> >  sound/soc/rockchip/rockchip_i2s.c | 72 +++++++++++++++++----------------------
>> >  1 file changed, 32 insertions(+), 40 deletions(-)
>> >
>> > diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
>> > index 83b1b9c..acc6225 100644
>> > --- a/sound/soc/rockchip/rockchip_i2s.c
>> > +++ b/sound/soc/rockchip/rockchip_i2s.c
>> > @@ -82,8 +82,8 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
>> >                                    I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
>> >
>> >                 regmap_update_bits(i2s->regmap, I2S_XFER,
>> > -                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START,
>> > -                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START);
>> > +                                  I2S_XFER_TXS_START,
>> > +                                  I2S_XFER_TXS_START);
>> >
>> >                 i2s->tx_start = true;
>> >         } else {
>> > @@ -92,27 +92,23 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
>> >                 regmap_update_bits(i2s->regmap, I2S_DMACR,
>> >                                    I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
>> >
>> > -               if (!i2s->rx_start) {
>> > -                       regmap_update_bits(i2s->regmap, I2S_XFER,
>> > -                                          I2S_XFER_TXS_START |
>> > -                                          I2S_XFER_RXS_START,
>> > -                                          I2S_XFER_TXS_STOP |
>> > -                                          I2S_XFER_RXS_STOP);
>> > +               regmap_update_bits(i2s->regmap, I2S_XFER,
>> > +                                  I2S_XFER_TXS_START,
>> > +                                  I2S_XFER_TXS_STOP);
>> >
>> > -                       regmap_update_bits(i2s->regmap, I2S_CLR,
>> > -                                          I2S_CLR_TXC | I2S_CLR_RXC,
>> > -                                          I2S_CLR_TXC | I2S_CLR_RXC);
>> > +               regmap_update_bits(i2s->regmap, I2S_CLR,
>> > +                                  I2S_CLR_TXC,
>> > +                                  I2S_CLR_TXC);
>> >
>> > -                       regmap_read(i2s->regmap, I2S_CLR, &val);
>> > +               regmap_read(i2s->regmap, I2S_CLR, &val);
>> >
>> > -                       /* Should wait for clear operation to finish */
>> > -                       while (val) {
>> > -                               regmap_read(i2s->regmap, I2S_CLR, &val);
>> > -                               retry--;
>> > -                               if (!retry) {
>> > -                                       dev_warn(i2s->dev, "fail to clear\n");
>> > -                                       break;
>> > -                               }
>> > +               /* Should wait for clear operation to finish */
>> > +               while (val & I2S_CLR_TXC) {
>> > +                       regmap_read(i2s->regmap, I2S_CLR, &val);
>> > +                       retry--;
>> > +                       if (!retry) {
>> > +                               dev_warn(i2s->dev, "fail to clear\n");
>> > +                               break;
>> >                         }
>> >                 }
>> >         }
>> > @@ -128,8 +124,8 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
>> >                                    I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
>> >
>> >                 regmap_update_bits(i2s->regmap, I2S_XFER,
>> > -                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START,
>> > -                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START);
>> > +                                  I2S_XFER_RXS_START,
>> > +                                  I2S_XFER_RXS_START);
>> >
>> >                 i2s->rx_start = true;
>> >         } else {
>> > @@ -138,27 +134,23 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
>> >                 regmap_update_bits(i2s->regmap, I2S_DMACR,
>> >                                    I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
>> >
>> > -               if (!i2s->tx_start) {
>> > -                       regmap_update_bits(i2s->regmap, I2S_XFER,
>> > -                                          I2S_XFER_TXS_START |
>> > -                                          I2S_XFER_RXS_START,
>> > -                                          I2S_XFER_TXS_STOP |
>> > -                                          I2S_XFER_RXS_STOP);
>> > +               regmap_update_bits(i2s->regmap, I2S_XFER,
>> > +                                  I2S_XFER_RXS_START,
>> > +                                  I2S_XFER_RXS_STOP);
>> >
>> > -                       regmap_update_bits(i2s->regmap, I2S_CLR,
>> > -                                          I2S_CLR_TXC | I2S_CLR_RXC,
>> > -                                          I2S_CLR_TXC | I2S_CLR_RXC);
>> > +               regmap_update_bits(i2s->regmap, I2S_CLR,
>> > +                                  I2S_CLR_RXC,
>> > +                                  I2S_CLR_RXC);
>> >
>> > -                       regmap_read(i2s->regmap, I2S_CLR, &val);
>> > +               regmap_read(i2s->regmap, I2S_CLR, &val);
>> >
>> > -                       /* Should wait for clear operation to finish */
>> > -                       while (val) {
>> > -                               regmap_read(i2s->regmap, I2S_CLR, &val);
>> > -                               retry--;
>> > -                               if (!retry) {
>> > -                                       dev_warn(i2s->dev, "fail to clear\n");
>> > -                                       break;
>> > -                               }
>> > +               /* Should wait for clear operation to finish */
>> > +               while (val & I2S_CLR_RXC) {
>> > +                       regmap_read(i2s->regmap, I2S_CLR, &val);
>> > +                       retry--;
>> > +                       if (!retry) {
>> > +                               dev_warn(i2s->dev, "fail to clear\n");
>> > +                               break;
>> >                         }
>> >                 }
>> >         }
>> > --
>> > 2.6.3.462.gbe2c914
>>
>> Using my Veyron Jerry Chromebook wiht latest kernel I found that the
>> speakers doesn't work. Bisect points to this patch as the offending
>> commit. However your changes looks reasonable the fact is that
>> reverting the patch makes the audio work again on my device. I need to
>> dig a bit more into the issue, but meanwhile, any idea on what is
>> happening ? Can I ask which device did you test?
>
> I tested this on a Radxa Rock2 square.  This change fixed an issue I
> found when running separate processes for playback and recording (I was
> testing with arecord and speaker-test IIRC) but I don't think that
> should be relevant.  I just read through the patch again and I can't see
> anything obviously wrong so I'm afraid I don't have any idea what's
> causing the problem you're seeing.
>

By chance, do you have a git repo containing the changes required to
test the sound on Radxa Rock2? Guess this is not in mainline.

Thanks,
 Enric

>
> John


From heiko at sntech.de  Mon May  2 09:36:20 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon,  2 May 2016 18:36:20 +0200
Subject: [RFC PATCH 1/3] clk: fix inconsistent use of req_rate
In-Reply-To: <1462206982-10444-1-git-send-email-heiko@sntech.de>
References: <1462206982-10444-1-git-send-email-heiko@sntech.de>
Message-ID: <1462206982-10444-2-git-send-email-heiko@sntech.de>

The req_rate property seems to be made to hold the rate requested through
clk_set_rate. Currently it gets initialized in clk_init to the clocks
current rate and then adapted in clk_set_rate calls. Orphan clocks and
their children get initialized to a rate of 0 and req_rate never gets
re-set when these lose their orphan-status.

Initializing req_rate to the clocks rate also is unintuitive as it just
copies the value that is already in the rate property and also looses the
information if a component actually requested a specific rate.

So separate the requested rate and only set it in clk_core_set_rate_nolock
when a real rate gets requested. The users of the req_rate __clk_put and
clk_set_rate_range that adjust a clock based on that value use req_rate
at first and fall back to rate if no rate had been requested now.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
 drivers/clk/clk.c | 24 ++++++++++++++++++------
 1 file changed, 18 insertions(+), 6 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index f079ea4..65e0aad 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1507,8 +1507,10 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
 		return 0;
 
 	/* bail early if nothing to do */
-	if (rate == clk_core_get_rate_nolock(core))
+	if (rate == clk_core_get_rate_nolock(core)) {
+		core->req_rate = req_rate;
 		return 0;
+	}
 
 	if ((core->flags & CLK_SET_RATE_GATE) && core->prepare_count)
 		return -EBUSY;
@@ -1599,9 +1601,14 @@ int clk_set_rate_range(struct clk *clk, unsigned long min, unsigned long max)
 	clk_prepare_lock();
 
 	if (min != clk->min_rate || max != clk->max_rate) {
+		unsigned long rate = clk->core->req_rate;
+
+		if (!rate)
+			rate = clk->core->rate;
+
 		clk->min_rate = min;
 		clk->max_rate = max;
-		ret = clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
+		ret = clk_core_set_rate_nolock(clk->core, rate);
 	}
 
 	clk_prepare_unlock();
@@ -2379,7 +2386,7 @@ static int __clk_core_init(struct clk_core *core)
 		rate = core->parent->rate;
 	else
 		rate = 0;
-	core->rate = core->req_rate = rate;
+	core->rate = rate;
 
 	/*
 	 * walk the list of orphan clocks and reparent any that newly finds a
@@ -2809,6 +2816,7 @@ int __clk_get(struct clk *clk)
 
 void __clk_put(struct clk *clk)
 {
+	unsigned long rate;
 	struct module *owner;
 
 	if (!clk || WARN_ON_ONCE(IS_ERR(clk)))
@@ -2817,9 +2825,13 @@ void __clk_put(struct clk *clk)
 	clk_prepare_lock();
 
 	hlist_del(&clk->clks_node);
-	if (clk->min_rate > clk->core->req_rate ||
-	    clk->max_rate < clk->core->req_rate)
-		clk_core_set_rate_nolock(clk->core, clk->core->req_rate);
+
+	rate = clk->core->req_rate;
+	if (!rate)
+		rate = clk->core->rate;
+
+	if (clk->min_rate > rate || clk->max_rate < rate)
+		clk_core_set_rate_nolock(clk->core, rate);
 
 	owner = clk->core->owner;
 	kref_put(&clk->core->ref, __clk_release);
-- 
2.8.0.rc3



From heiko at sntech.de  Mon May  2 09:36:21 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon,  2 May 2016 18:36:21 +0200
Subject: [RFC PATCH 2/3] clk: adjust clocks to their requested rate after
 parent changes
In-Reply-To: <1462206982-10444-1-git-send-email-heiko@sntech.de>
References: <1462206982-10444-1-git-send-email-heiko@sntech.de>
Message-ID: <1462206982-10444-3-git-send-email-heiko@sntech.de>

Given a hirarchy of clk1 -> [div] -> clk2, when the rate of clk1 gets
changed, clk2 changes as well as the divider stays the same. There may
be cases where a user of clk2 needs it at a specific rate, so clk2
needs to be readjusted for the changed rate of clk1.

So if a rate was requested for the clock, and its rate changed during
the underlying rate-change, with this change the clock framework now
tries to readjust the rate back to/near the requested one.

The whole process is protected by a new clock-flag to not force this
behaviour change onto every clock defined in the ccf.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
 drivers/clk/clk.c            | 13 +++++++++++--
 include/linux/clk-provider.h |  1 +
 2 files changed, 12 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
index 65e0aad..22be369 100644
--- a/drivers/clk/clk.c
+++ b/drivers/clk/clk.c
@@ -1410,6 +1410,9 @@ static struct clk_core *clk_propagate_rate_change(struct clk_core *core,
 	return fail_clk;
 }
 
+static int clk_core_set_rate_nolock(struct clk_core *core,
+				    unsigned long req_rate);
+
 /*
  * walk down a subtree and set the new rates notifying the rate
  * change on the way
@@ -1494,6 +1497,12 @@ static void clk_change_rate(struct clk_core *core)
 	/* handle the new child who might not be in core->children yet */
 	if (core->new_child)
 		clk_change_rate(core->new_child);
+
+	/* handle a changed clock that needs to readjust its rate */
+	if (core->flags & CLK_KEEP_REQ_RATE && core->req_rate
+					    && core->new_rate != old_rate
+					    && core->new_rate != core->req_rate)
+		clk_core_set_rate_nolock(core, core->req_rate);
 }
 
 static int clk_core_set_rate_nolock(struct clk_core *core,
@@ -1529,11 +1538,11 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
 		return -EBUSY;
 	}
 
+	core->req_rate = req_rate;
+
 	/* change the rates */
 	clk_change_rate(top);
 
-	core->req_rate = req_rate;
-
 	return ret;
 }
 
diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
index 0c72204..06f189e 100644
--- a/include/linux/clk-provider.h
+++ b/include/linux/clk-provider.h
@@ -33,6 +33,7 @@
 #define CLK_RECALC_NEW_RATES	BIT(9) /* recalc rates after notifications */
 #define CLK_SET_RATE_UNGATE	BIT(10) /* clock needs to run to set rate */
 #define CLK_IS_CRITICAL		BIT(11) /* do not gate, ever */
+#define CLK_KEEP_REQ_RATE	BIT(12) /* keep reqrate on parent rate change */
 
 struct clk;
 struct clk_hw;
-- 
2.8.0.rc3



From heiko at sntech.de  Mon May  2 09:36:22 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon,  2 May 2016 18:36:22 +0200
Subject: [RFC PATCH 3/3] clk: rockchip: make rk3399 vop dclks keep their rate
 on parent rate changes
In-Reply-To: <1462206982-10444-1-git-send-email-heiko@sntech.de>
References: <1462206982-10444-1-git-send-email-heiko@sntech.de>
Message-ID: <1462206982-10444-4-git-send-email-heiko@sntech.de>

The rk3399 hdmi phy is supplied by the vpll directly and needs to adapt
that frequency depending on the selected resolution on the hdmi output.
For the hdmi-phy the vpll frequency is supplied unchanged without
any dividers being present there.

The vpll also is one of the sources the general display clock of the
visual output processor (vop) and as it is somewhat special for
display operations possibly also the preferred pll source. Here a divider
is available between the pll-mux and the vop clock, so that this part
can adapt the resulting frequency if needed.

So to keep the vop clock in line with the target rate, set the newly
introduced CLK_KEEP_REQ_RATE flag for the dclk_vop clocks on rk3399.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
 drivers/clk/rockchip/clk-rk3399.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
index 5248726..4462a50 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -277,11 +277,11 @@ static struct rockchip_clk_branch rk3399_uart4_pmu_fracmux __initdata =
 			RK3399_PMU_CLKSEL_CON(5), 8, 2, MFLAGS);
 
 static struct rockchip_clk_branch rk3399_dclk_vop0_fracmux __initdata =
-	MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT,
+	MUX(DCLK_VOP0, "dclk_vop0", mux_dclk_vop0_p, CLK_SET_RATE_PARENT | CLK_KEEP_REQ_RATE,
 			RK3399_CLKSEL_CON(49), 11, 1, MFLAGS);
 
 static struct rockchip_clk_branch rk3399_dclk_vop1_fracmux __initdata =
-	MUX(DCLK_VOP1, "dclk_vop1", mux_dclk_vop1_p, CLK_SET_RATE_PARENT,
+	MUX(DCLK_VOP1, "dclk_vop1", mux_dclk_vop1_p, CLK_SET_RATE_PARENT | CLK_KEEP_REQ_RATE,
 			RK3399_CLKSEL_CON(50), 11, 1, MFLAGS);
 
 static struct rockchip_clk_branch rk3399_pmuclk_wifi_fracmux __initdata =
-- 
2.8.0.rc3



From heiko at sntech.de  Mon May  2 09:36:19 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon,  2 May 2016 18:36:19 +0200
Subject: [RFC PATCH 0/3] clk: attempt to keep requested rate on parent changes
Message-ID: <1462206982-10444-1-git-send-email-heiko@sntech.de>

I remember reading about people discussing that problem in the past, but
haven't been able to find another approach to it yet [or I'm just blind
as happens to often].

Our problem is the following clock structure:

[anotherPLL]
    |
    ------ [div] ----- dclk_vop
    |
[   vpll   ] --------- hdmi_phy


We need to set the vpll dynamically but still want to retain

The other option that comes to mind, would be to have a clock-notifier,
in the drm driver, but calling clk_set_rate from their looks like it
shouldn't work due to the prepare mutex already being held.


The whole thing is labeled RFC because while it works for us and solves
the problem, I'm not sure if I'm overlooking some important aspect or
am interferring with some other planned approach for that issue.


Heiko Stuebner (3):
  clk: fix inconsistent use of req_rate
  clk: adjust clocks to their requested rate after parent changes
  clk: rockchip: make rk3399 vop dclks keep their rate on parent rate changes

 drivers/clk/clk.c                 | 37 +++++++++++++++++++++++++++++--------
 drivers/clk/rockchip/clk-rk3399.c |  4 ++--
 include/linux/clk-provider.h      |  1 +
 3 files changed, 32 insertions(+), 10 deletions(-)

-- 
2.8.0.rc3



From sboyd at codeaurora.org  Mon May  2 16:52:22 2016
From: sboyd at codeaurora.org (Stephen Boyd)
Date: Mon, 2 May 2016 16:52:22 -0700
Subject: [GIT PULL] rockchip clock changes for 4.7 part 3 - some more fixes
In-Reply-To: <3990329.NB1U7jJjZj@diego>
References: <3990329.NB1U7jJjZj@diego>
Message-ID: <20160502234622.GA3492@codeaurora.org>

On 04/29, Heiko St?bner wrote:
> Hi Mike, Stephen,
> 
> some more fixes for the new rk3399 have come up addressing small errors
> found in the manual during bringup of the soc, so please pull.
> 
> 

Thanks. Pulled.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From wxt at rock-chips.com  Mon May  2 19:23:50 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Tue,  3 May 2016 10:23:50 +0800
Subject: [PATCH] thermal: rockchip: use the usleep_range instead of udelay
Message-ID: <1462242230-20873-1-git-send-email-wxt@rock-chips.com>

Documentation/timers/timers-howto.txt recommends to use
usleep_range on delays > 10usec.
The usleep_range indeed reduces CPU load, since the udelay will busy wait
for enough loop cycles to achieve the desired delay.

Fixes commit b06c52db39fd ("thermal: rockchip:
handle the power sequence for tsadc controller").

Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: Heiko Stuebner <heiko at sntech.de>
Suggested-by: Eduardo Valentin <edubezval at gmail.com>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>

---

 drivers/thermal/rockchip_thermal.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index 86a1ab0..5d491f1 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -547,10 +547,10 @@ static void rk_tsadcv3_initialize(struct regmap *grf, void __iomem *regs,
 		regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_ON);
 		mdelay(10);
 		regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_OFF);
-		udelay(100); /* The spec note says at least 15 us */
+		usleep_range(15, 100); /* The spec note says at least 15 us */
 		regmap_write(grf, GRF_SARADC_TESTBIT, GRF_SARADC_TESTBIT_ON);
 		regmap_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_TESTBIT_H_ON);
-		udelay(200); /* The spec note says at least 90 us */
+		usleep_range(90, 200); /* The spec note says at least 90 us */
 	}
 
 	if (tshut_polarity == TSHUT_HIGH_ACTIVE)
-- 
1.9.1



From caesar.upstream at gmail.com  Mon May  2 19:27:26 2016
From: caesar.upstream at gmail.com (Caesar Wang)
Date: Tue, 3 May 2016 10:27:26 +0800
Subject: [PATCH 4/9] thermal: rockchip: handle the power sequence for
 tsadc controller
In-Reply-To: <20160428150432.GA20009@localhost.localdomain>
References: <1460950562-20652-1-git-send-email-wxt@rock-chips.com>
 <1460950562-20652-5-git-send-email-wxt@rock-chips.com>
 <20160427234818.GB2590@localhost.localdomain> <57216C65.5040501@gmail.com>
 <20160428150432.GA20009@localhost.localdomain>
Message-ID: <57280C8E.5080406@gmail.com>



? 2016?04?28? 23:04, Eduardo Valentin ??:
> On Thu, Apr 28, 2016 at 09:50:29AM +0800, Caesar Wang wrote:
>>
>> ? 2016?04?28? 07:48, Eduardo Valentin ??:
>>> On Mon, Apr 18, 2016 at 11:35:56AM +0800, Caesar Wang wrote:
>>>> +		regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_ON);
>>>> +		mdelay(10);
>>>> +		regmap_write(grf, GRF_TSADC_TESTBIT_L, GRF_TSADC_TSEN_PD_OFF);
>>>> +		udelay(100); /* The spec note says at least 15 us */
>>>> +		regmap_write(grf, GRF_SARADC_TESTBIT, GRF_SARADC_TESTBIT_ON);
>>>> +		regmap_write(grf, GRF_TSADC_TESTBIT_H, GRF_TSADC_TESTBIT_H_ON);
>>>> +		udelay(200); /* The spec note says at least 90 us */
>>> Does it make sense to use usleep_range() instead?
>> I think so in the past, but I'm digging into the the udelay/usleep for
>> kernel.
> What do you mean by in the past? timekeeping doc still recommends the
> range 10us to 20ms for usleep_range()
>
>> In general,
>>
>> udelay < 10us ~100us
>> mdelay > 1m, <1000ms/HZ
>> usleep_range(min,max) > 100us, <20ms
> even here, your udelays could be replaced by usleep_range().
>
> Any particular reason you believe spining is better than sleeping in
> your case?
>
>> msleep > 20ms,  < 1000ms
>>
>> So the udelay is suit for tsadc power sequence.
>> ---
>>
>>
>> Also,  we have used the mdelay(10), so it doesn't matter if use the udelay.
>> After all the udelay is stable than the usleep_range.
> What do you mean udelay is stable than usleep_range? usleep_range will
> give the opportunity to the scheduler to coalesce wakeups. udelay is a
> busyloop spin. Besides, I am not sure the current situation, but
> busylooping may be affected by cpu frequency.

Okay, thanks for pointing out.

Send the fixes patch on https://patchwork.kernel.org/patch/8999971/

Thank you!


-Caesar
>
>> -Caesar
>>
>>> 1.9.1
>>>
>>>
>>>
>>>
>>> -- 
>>> Thanks,
>>> Caesar
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip


-- 
Thanks,
Caesar



From sugar.zhang at rock-chips.com  Mon May  2 21:12:34 2016
From: sugar.zhang at rock-chips.com (sugar)
Date: Tue, 3 May 2016 12:12:34 +0800
Subject: [PATCH 1/2] ASoC: rockchip: i2s: separate capture and playback
In-Reply-To: <20160430070049.GF14612@serenity.lan>
References: <1449657147-26959-1-git-send-email-john@metanate.com>
 <CAFqH_52C4JKno4uyt54UdWKAJKM4FPGRiQaQQ9_H-Mz1Cr+Hqg@mail.gmail.com>
 <20160430070049.GF14612@serenity.lan>
Message-ID: <57282532.7000402@rock-chips.com>

Hi John,

On 4/30/2016 15:00, John Keeping Wrote:
> Hi Enric,
>
> On Fri, Apr 29, 2016 at 04:59:27PM +0200, Enric Balletbo Serra wrote:
>> 2015-12-09 11:32 GMT+01:00 John Keeping <john at metanate.com>:
>>> If we only clear the tx/rx state when both are disabled it is not
>>> possible to start/stop one multiple times while the other is running.
>>> Since the two are independently controlled, treat them as such and
>>> remove the false dependency between capture and playback.
>>>
>>> Signed-off-by: John Keeping <john at metanate.com>
>>> ---
>>>   sound/soc/rockchip/rockchip_i2s.c | 72 +++++++++++++++++----------------------
>>>   1 file changed, 32 insertions(+), 40 deletions(-)
>>>
>>> diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
>>> index 83b1b9c..acc6225 100644
>>> --- a/sound/soc/rockchip/rockchip_i2s.c
>>> +++ b/sound/soc/rockchip/rockchip_i2s.c
>>> @@ -82,8 +82,8 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
>>>                                     I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
>>>
>>>                  regmap_update_bits(i2s->regmap, I2S_XFER,
>>> -                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START,
>>> -                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START);
>>> +                                  I2S_XFER_TXS_START,
>>> +                                  I2S_XFER_TXS_START);
>>>
>>>                  i2s->tx_start = true;
>>>          } else {
>>> @@ -92,27 +92,23 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
>>>                  regmap_update_bits(i2s->regmap, I2S_DMACR,
>>>                                     I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
>>>
>>> -               if (!i2s->rx_start) {
>>> -                       regmap_update_bits(i2s->regmap, I2S_XFER,
>>> -                                          I2S_XFER_TXS_START |
>>> -                                          I2S_XFER_RXS_START,
>>> -                                          I2S_XFER_TXS_STOP |
>>> -                                          I2S_XFER_RXS_STOP);
>>> +               regmap_update_bits(i2s->regmap, I2S_XFER,
>>> +                                  I2S_XFER_TXS_START,
>>> +                                  I2S_XFER_TXS_STOP);
>>>
>>> -                       regmap_update_bits(i2s->regmap, I2S_CLR,
>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC,
>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC);
>>> +               regmap_update_bits(i2s->regmap, I2S_CLR,
>>> +                                  I2S_CLR_TXC,
>>> +                                  I2S_CLR_TXC);
>>>
>>> -                       regmap_read(i2s->regmap, I2S_CLR, &val);
>>> +               regmap_read(i2s->regmap, I2S_CLR, &val);
>>>
>>> -                       /* Should wait for clear operation to finish */
>>> -                       while (val) {
>>> -                               regmap_read(i2s->regmap, I2S_CLR, &val);
>>> -                               retry--;
>>> -                               if (!retry) {
>>> -                                       dev_warn(i2s->dev, "fail to clear\n");
>>> -                                       break;
>>> -                               }
>>> +               /* Should wait for clear operation to finish */
>>> +               while (val & I2S_CLR_TXC) {
>>> +                       regmap_read(i2s->regmap, I2S_CLR, &val);
>>> +                       retry--;
>>> +                       if (!retry) {
>>> +                               dev_warn(i2s->dev, "fail to clear\n");
>>> +                               break;
>>>                          }
>>>                  }
>>>          }
>>> @@ -128,8 +124,8 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
>>>                                     I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
>>>
>>>                  regmap_update_bits(i2s->regmap, I2S_XFER,
>>> -                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START,
>>> -                                  I2S_XFER_TXS_START | I2S_XFER_RXS_START);
>>> +                                  I2S_XFER_RXS_START,
>>> +                                  I2S_XFER_RXS_START);
>>>
>>>                  i2s->rx_start = true;
>>>          } else {
>>> @@ -138,27 +134,23 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
>>>                  regmap_update_bits(i2s->regmap, I2S_DMACR,
>>>                                     I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
>>>
>>> -               if (!i2s->tx_start) {
>>> -                       regmap_update_bits(i2s->regmap, I2S_XFER,
>>> -                                          I2S_XFER_TXS_START |
>>> -                                          I2S_XFER_RXS_START,
>>> -                                          I2S_XFER_TXS_STOP |
>>> -                                          I2S_XFER_RXS_STOP);
>>> +               regmap_update_bits(i2s->regmap, I2S_XFER,
>>> +                                  I2S_XFER_RXS_START,
>>> +                                  I2S_XFER_RXS_STOP);
>>>
>>> -                       regmap_update_bits(i2s->regmap, I2S_CLR,
>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC,
>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC);
>>> +               regmap_update_bits(i2s->regmap, I2S_CLR,
>>> +                                  I2S_CLR_RXC,
>>> +                                  I2S_CLR_RXC);
>>>
>>> -                       regmap_read(i2s->regmap, I2S_CLR, &val);
>>> +               regmap_read(i2s->regmap, I2S_CLR, &val);
>>>
>>> -                       /* Should wait for clear operation to finish */
>>> -                       while (val) {
>>> -                               regmap_read(i2s->regmap, I2S_CLR, &val);
>>> -                               retry--;
>>> -                               if (!retry) {
>>> -                                       dev_warn(i2s->dev, "fail to clear\n");
>>> -                                       break;
>>> -                               }
>>> +               /* Should wait for clear operation to finish */
>>> +               while (val & I2S_CLR_RXC) {
>>> +                       regmap_read(i2s->regmap, I2S_CLR, &val);
>>> +                       retry--;
>>> +                       if (!retry) {
>>> +                               dev_warn(i2s->dev, "fail to clear\n");
>>> +                               break;
>>>                          }
>>>                  }
>>>          }
>>> --
>>> 2.6.3.462.gbe2c914
>>
>> Using my Veyron Jerry Chromebook wiht latest kernel I found that the
>> speakers doesn't work. Bisect points to this patch as the offending
>> commit. However your changes looks reasonable the fact is that
>> reverting the patch makes the audio work again on my device. I need to
>> dig a bit more into the issue, but meanwhile, any idea on what is
>> happening ? Can I ask which device did you test?
>
> I tested this on a Radxa Rock2 square.  This change fixed an issue I
> found when running separate processes for playback and recording (I was
> testing with arecord and speaker-test IIRC) but I don't think that
> should be relevant.  I just read through the patch again and I can't see
> anything obviously wrong so I'm afraid I don't have any idea what's
> causing the problem you're seeing.
>
Do you have test playback/capture at the same time? I think you may 
reproduce this issue if you do as follows:

step 1: tinyplay test.wav -D 0 -d 0 -p 1024 -n 4 &
step 2: tinycap r.wav -D 0 -d 0 -p 1024 -n 4 &

you will find that there is no music now.

because of this problem, we enable tx/rx at the same time to WA this issue.

May I know what's the issue that you met before?
>
> John
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
>
>



From caesar.upstream at gmail.com  Mon May  2 23:19:10 2016
From: caesar.upstream at gmail.com (Caesar Wang)
Date: Tue, 3 May 2016 14:19:10 +0800
Subject: [PATCH 1/4] thermal: Add support for hardware-tracked trip points
In-Reply-To: <20160427214843.GA6438@localhost.localdomain>
References: <1461553367-24744-1-git-send-email-wxt@rock-chips.com>
 <1461553367-24744-2-git-send-email-wxt@rock-chips.com>
 <20160427214843.GA6438@localhost.localdomain>
Message-ID: <572842DE.7080301@gmail.com>



? 2016?04?28? 05:48, Eduardo Valentin ??:
> A couple of comments as follows,
>
> On Mon, Apr 25, 2016 at 11:02:44AM +0800, Caesar Wang wrote:
>> From: Sascha Hauer <s.hauer at pengutronix.de>
>>
>> This adds support for hardware-tracked trip points to the device tree
>> thermal sensor framework.
>>
>> The framework supports an arbitrary number of trip points. Whenever
>> the current temperature is updated, the trip points immediately
>> below and above the current temperature are found. A .set_trips
>> callback is then called with the temperatures. If there is no trip
>> point above or below the current temperature, the passed trip
>> temperature will be -INT_MAX or INT_MAX respectively. In this callback,
>> the driver should program the hardware such that it is notified
>> when either of these trip points are triggered. When a trip point
>> is triggered, the driver should call `thermal_zone_device_update'
>> for the respective thermal zone. This will cause the trip points
>> to be updated again.
>>
>> If .set_trips is not implemented, the framework behaves as before.
>>
>> This patch is based on an earlier version from Mikko Perttunen
>> <mikko.perttunen at kapsi.fi>
>>
>> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>> Cc: Zhang Rui <rui.zhang at intel.com>
>> Cc: Eduardo Valentin <edubezval at gmail.com>
>> Cc: linux-pm at vger.kernel.org
>> ---
>>
>>   drivers/thermal/thermal_core.c | 48 ++++++++++++++++++++++++++++++++++++++++++
>>   include/linux/thermal.h        |  3 +++
> Given that this is adding a new feature in the framework, I would prefer
> if you could also describe the .set_trips() in the sysfs-api.txt
> documentation file.

Okay, done.
>
> A short description of the expectation of what the framework is going to
> do is also welcome. For example, are drivers supposed to setup the
> polling together with the threshold based approach?
>
>>   2 files changed, 51 insertions(+)
>>
>> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
>> index f1db496..cfef8cc 100644
>> --- a/drivers/thermal/thermal_core.c
>> +++ b/drivers/thermal/thermal_core.c
>> @@ -520,6 +520,47 @@ exit:
>>   }
>>   EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
>>   
>> +static void thermal_zone_set_trips(struct thermal_zone_device *tz)
>> +{
>> +	int low = -INT_MAX;
>> +	int high = INT_MAX;
>> +	int trip_temp, hysteresis;
>> +	int temp = tz->temperature;
>> +	int i, ret;
>> +
>> +	if (!tz->ops->set_trips)
>> +		return;
>> +
>> +	for (i = 0; i < tz->trips; i++) {
>> +		int trip_low;
>> +
>> +		tz->ops->get_trip_temp(tz, i, &trip_temp);
>> +		tz->ops->get_trip_hyst(tz, i, &hysteresis);
>> +
>> +		trip_low = trip_temp - hysteresis;
>> +
>> +		if (trip_low < temp && trip_low > low)
>> +			low = trip_low;
>> +
>> +		if (trip_temp > temp && trip_temp < high)
>> +			high = trip_temp;
>> +	}
> Did I understand correctly that you will be flooded by IRQs when you
> have:
> 1. One single trip point.
> 2. Your temp is above trip_temp
>
> With the above, you would program as threshold:
> high == trip_temp
> low == trip_temp - hyst
>
> And the IRQ would fire immediattely, causing a device update, causing a
> reprogramming, causing another irq, and this would continue, until the
> temperature goes below trip_temp, right?

Right, As the example tested by the rockchip platform. (70/75/ degree is 
the trip point)

..
[  663.984327] rockchip-thermal ff260000.tsadc: sensor 0 - temp: 66111, 
retval: 0
[  664.048326] rockchip-thermal ff260000.tsadc: sensor 1 - temp: 68333, 
retval: 0
[  664.055600] rockchip-thermal ff260000.tsadc: 
rockchip_thermal_set_trips: sensor 1: low: 68000, high 70000
[  664.992322] rockchip-thermal ff260000.tsadc: sensor 0 - temp: 68888, 
retval: 0
[  664.999579] rockchip-thermal ff260000.tsadc: 
rockchip_thermal_set_trips: sensor 0: low: 68000, high 70000
[  665.066322] rockchip-thermal ff260000.tsadc: sensor 1 - temp: 68333, 
retval: 0
...

[ 4250.474102] rockchip-thermal ff260000.tsadc: sensor 0 - temp: 73333, 
retval: 0
[ 4250.481432] rockchip-thermal ff260000.tsadc: sensor 1 - temp: 74444, 
retval: 0
[ 4250.488792] rockchip-thermal ff260000.tsadc: 
rockchip_thermal_set_trips: sensor 1: low: 73000, high 75000
[ 4250.581360] rockchip-thermal ff260000.tsadc: sensor 0 - temp: 72777, 
retval: 0
[ 4250.588767] rockchip-thermal ff260000.tsadc: 
rockchip_thermal_set_trips: sensor 0: low: 68000, high 75000
[ 4250.598735] rockchip-thermal ff260000.tsadc: sensor 1 - temp: 75000, 
retval: 0
[ 4250.606065] rockchip-thermal ff260000.tsadc: 
rockchip_thermal_set_trips: sensor 1: low: 73000, high 95000
...


>> +
>> +	/* No need to change trip points */
>> +	if (tz->prev_low_trip == low && tz->prev_high_trip == high)
>> +		return;
>> +
>> +	tz->prev_low_trip = low;
>> +	tz->prev_high_trip = high;
>> +
>> +	dev_dbg(&tz->device, "new temperature boundaries: %d < x < %d\n",
>> +			low, high);
>> +
>> +	ret = tz->ops->set_trips(tz, low, high);
>> +	if (ret)
>> +		dev_err(&tz->device, "Failed to set trips: %d\n", ret);
>> +}
>> +
>>   static void update_temperature(struct thermal_zone_device *tz)
>>   {
>>   	int temp, ret;
>> @@ -569,6 +610,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
>>   
>>   	update_temperature(tz);
>>   
>> +	thermal_zone_set_trips(tz);
>> +
>>   	for (count = 0; count < tz->trips; count++)
>>   		handle_thermal_trip(tz, count);
>>   }
>> @@ -754,6 +797,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
>>   	 */
>>   	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
>>   
>> +	if (!ret)
>> +		thermal_zone_set_trips(tz);
>> +
> You would probably want to do the same on trip_point_temp_store().

Sure.
>>   	return ret ? ret : count;
>>   }
>>   
>> @@ -1843,6 +1889,8 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
>>   	tz->trips = trips;
>>   	tz->passive_delay = passive_delay;
>>   	tz->polling_delay = polling_delay;
>> +	tz->prev_low_trip = INT_MAX;
>> +	tz->prev_high_trip = -INT_MAX;
>>   	/* A new thermal zone needs to be updated anyway. */
>>   	atomic_set(&tz->need_update, 1);
>>   
>> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
>> index e45abe7..e258359 100644
>> --- a/include/linux/thermal.h
>> +++ b/include/linux/thermal.h
>> @@ -98,6 +98,7 @@ struct thermal_zone_device_ops {
>>   	int (*unbind) (struct thermal_zone_device *,
>>   		       struct thermal_cooling_device *);
>>   	int (*get_temp) (struct thermal_zone_device *, int *);
>> +	int (*set_trips) (struct thermal_zone_device *, int, int);
>>   	int (*get_mode) (struct thermal_zone_device *,
>>   			 enum thermal_device_mode *);
>>   	int (*set_mode) (struct thermal_zone_device *,
>> @@ -199,6 +200,8 @@ struct thermal_zone_device {
>>   	int last_temperature;
>>   	int emul_temperature;
>>   	int passive;
>> +	int prev_low_trip;
>> +	int prev_high_trip;
>>   	unsigned int forced_passive;
>>   	atomic_t need_update;
>>   	struct thermal_zone_device_ops *ops;
>> -- 
>> 1.9.1
>>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip


-- 
Thanks,
Caesar



From mark.yao at rock-chips.com  Mon May  2 23:21:39 2016
From: mark.yao at rock-chips.com (Mark yao)
Date: Tue, 3 May 2016 14:21:39 +0800
Subject: [GIT PULL] drm/rockchip: some fixes
Message-ID: <57284373.9090005@rock-chips.com>

Hi Dave
     Here are some little fixes for rockchip drm, looks good for me, and 
seems there is no doubt on them, So I'd like you can land them.

The following changes since commit b89359bdf0f1e95a4c5f92300594ba9dde323fc4:

   Merge branch 'for-next' of http://git.agner.ch/git/linux-drm-fsl-dcu 
into drm-next (2016-04-29 14:57:51 +1000)

are available in the git repository at:


   https://github.com/markyzq/kernel-drm-rockchip.git 
drm-rockchip-next-fixes-05-03

for you to fetch changes up to 2db00cf5a07b7c543392ff88163428509cda38ae:

   drm/rockchip: vop: Initialize vskiplines to zero (2016-05-03 14:11:23 
+0800)

----------------------------------------------------------------
Dan Carpenter (1):
       drm/rockchip: inno_hdmi: fix an error code

John Keeping (2):
       drm/rockchip: remove redundant statement
       drm/rockchip: don't leak iommu mapping

Mark Yao (4):
       drm/rockchip: get rid of rockchip_drm_crtc_mode_config
       drm/rockchip: support non-iommu buffer path
       drm/rockchip: vop: fix iommu crash with async atomic
       drm/rockchip: vop: Initialize vskiplines to zero

  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 48 
+++++++++++++++++++++++++++---------------------
  drivers/gpu/drm/rockchip/dw-mipi-dsi.c          | 38 
++++++++++++++++++++++++--------------
  drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c     | 17 ++++++++++++++---
  drivers/gpu/drm/rockchip/inno_hdmi.c            | 20 ++++++++++++++++----
  drivers/gpu/drm/rockchip/rockchip_drm_drv.c     | 66 
+++++++++++++++++++++++++++++++++++++++++++++++-------------------
  drivers/gpu/drm/rockchip/rockchip_drm_drv.h     | 10 ++++++++--
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c     | 95 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------------
  7 files changed, 196 insertions(+), 98 deletions(-)

-- 
?ark Yao




From wxt at rock-chips.com  Mon May  2 23:32:46 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Tue, 3 May 2016 14:32:46 +0800
Subject: [PATCH 2/4] thermal: of: implement .set_trips for device tree
 thermal zones
In-Reply-To: <20160427215209.GC6438@localhost.localdomain>
References: <1461553367-24744-1-git-send-email-wxt@rock-chips.com>
 <1461553367-24744-3-git-send-email-wxt@rock-chips.com>
 <20160427215209.GC6438@localhost.localdomain>
Message-ID: <5728460E.4000009@rock-chips.com>



? 2016?04?28? 05:52, Eduardo Valentin ??:
> On Mon, Apr 25, 2016 at 11:02:45AM +0800, Caesar Wang wrote:
>> From: Sascha Hauer <s.hauer at pengutronix.de>
>>
>> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>> Cc: Zhang Rui <rui.zhang at intel.com>
>> Cc: Eduardo Valentin <edubezval at gmail.com>
>> Cc: linux-pm at vger.kernel.org
>> ---
>>
>>   drivers/thermal/of-thermal.c | 12 ++++++++++++
>>   include/linux/thermal.h      |  4 ++++
>>   2 files changed, 16 insertions(+)
>>
>> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
>> index b8e509c..8722e63 100644
>> --- a/drivers/thermal/of-thermal.c
>> +++ b/drivers/thermal/of-thermal.c
>> @@ -101,6 +101,17 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
>>   	return data->ops->get_temp(data->sensor_data, temp);
>>   }
>>   
>> +static int of_thermal_set_trips(struct thermal_zone_device *tz,
>> +				int low, int high)
>> +{
>> +	struct __thermal_zone *data = tz->devdata;
>> +
>> +	if (!data->ops || !data->ops->set_trips)
>> +		return -EINVAL;
>> +
>> +	return data->ops->set_trips(data->sensor_data, low, high);
>> +}
>> +
>>   /**
>>    * of_thermal_get_ntrips - function to export number of available trip
>>    *			   points.
>> @@ -427,6 +438,7 @@ thermal_zone_of_add_sensor(struct device_node *zone,
>>   
>>   	tzd->ops->get_temp = of_thermal_get_temp;
>>   	tzd->ops->get_trend = of_thermal_get_trend;
>> +	tzd->ops->set_trips = of_thermal_set_trips;
>>   	tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
>>   	mutex_unlock(&tzd->lock);
>>   
>> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
>> index e258359..cb64866 100644
>> --- a/include/linux/thermal.h
>> +++ b/include/linux/thermal.h
>> @@ -336,12 +336,16 @@ struct thermal_genl_event {
>>    *
>>    * Optional:
>>    * @get_trend: a pointer to a function that reads the sensor temperature trend.
>> + * @@set_trips: a pointer to a function that sets a temperature window. When
>> + *		this window is left the driver must inform the thermal core via
>> + *              thermal_zone_device_update.
> Ok. We start to see some documentation and expectation being stated
> here. Nice. Please respin the comment on thermal core too, so drivers
> that dont use OF will also be aware of this feature and how to use them.

Okay, done

>
>>    * @set_emul_temp: a pointer to a function that sets sensor emulated
>>    *		   temperature.
>>    */
>>   struct thermal_zone_of_device_ops {
>>   	int (*get_temp)(void *, int *);
>>   	int (*get_trend)(void *, long *);
>> +	int (*set_trips)(void *, int, int);
>>   	int (*set_emul_temp)(void *, int);
>>   	int (*set_trip_temp)(void *, int, int);
>>   };
>> -- 
>> 1.9.1
>>
>
>

-- 
caesar wang | software engineer | wxt at rock-chip.com




From eballetbo at gmail.com  Tue May  3 02:16:58 2016
From: eballetbo at gmail.com (Enric Balletbo Serra)
Date: Tue, 3 May 2016 11:16:58 +0200
Subject: [alsa-devel] [PATCH 1/2] ASoC: rockchip: i2s: separate capture
 and playback
In-Reply-To: <57282532.7000402@rock-chips.com>
References: <1449657147-26959-1-git-send-email-john@metanate.com>
 <CAFqH_52C4JKno4uyt54UdWKAJKM4FPGRiQaQQ9_H-Mz1Cr+Hqg@mail.gmail.com>
 <20160430070049.GF14612@serenity.lan>
 <57282532.7000402@rock-chips.com>
Message-ID: <CAFqH_50D5PQOkpCDefds3Nyktvitoe2Wx=YcXM2POox1ooO=0g@mail.gmail.com>

Hi all,

2016-05-03 6:12 GMT+02:00 sugar <sugar.zhang at rock-chips.com>:
> Hi John,
>
>
> On 4/30/2016 15:00, John Keeping Wrote:
>>
>> Hi Enric,
>>
>> On Fri, Apr 29, 2016 at 04:59:27PM +0200, Enric Balletbo Serra wrote:
>>>
>>> 2015-12-09 11:32 GMT+01:00 John Keeping <john at metanate.com>:
>>>>
>>>> If we only clear the tx/rx state when both are disabled it is not
>>>> possible to start/stop one multiple times while the other is running.
>>>> Since the two are independently controlled, treat them as such and
>>>> remove the false dependency between capture and playback.
>>>>
>>>> Signed-off-by: John Keeping <john at metanate.com>
>>>> ---
>>>>   sound/soc/rockchip/rockchip_i2s.c | 72
>>>> +++++++++++++++++----------------------
>>>>   1 file changed, 32 insertions(+), 40 deletions(-)
>>>>
>>>> diff --git a/sound/soc/rockchip/rockchip_i2s.c
>>>> b/sound/soc/rockchip/rockchip_i2s.c
>>>> index 83b1b9c..acc6225 100644
>>>> --- a/sound/soc/rockchip/rockchip_i2s.c
>>>> +++ b/sound/soc/rockchip/rockchip_i2s.c
>>>> @@ -82,8 +82,8 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev
>>>> *i2s, int on)
>>>>                                     I2S_DMACR_TDE_ENABLE,
>>>> I2S_DMACR_TDE_ENABLE);
>>>>
>>>>                  regmap_update_bits(i2s->regmap, I2S_XFER,
>>>> -                                  I2S_XFER_TXS_START |
>>>> I2S_XFER_RXS_START,
>>>> -                                  I2S_XFER_TXS_START |
>>>> I2S_XFER_RXS_START);
>>>> +                                  I2S_XFER_TXS_START,
>>>> +                                  I2S_XFER_TXS_START);
>>>>
>>>>                  i2s->tx_start = true;
>>>>          } else {
>>>> @@ -92,27 +92,23 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev
>>>> *i2s, int on)
>>>>                  regmap_update_bits(i2s->regmap, I2S_DMACR,
>>>>                                     I2S_DMACR_TDE_ENABLE,
>>>> I2S_DMACR_TDE_DISABLE);
>>>>
>>>> -               if (!i2s->rx_start) {
>>>> -                       regmap_update_bits(i2s->regmap, I2S_XFER,
>>>> -                                          I2S_XFER_TXS_START |
>>>> -                                          I2S_XFER_RXS_START,
>>>> -                                          I2S_XFER_TXS_STOP |
>>>> -                                          I2S_XFER_RXS_STOP);
>>>> +               regmap_update_bits(i2s->regmap, I2S_XFER,
>>>> +                                  I2S_XFER_TXS_START,
>>>> +                                  I2S_XFER_TXS_STOP);
>>>>
>>>> -                       regmap_update_bits(i2s->regmap, I2S_CLR,
>>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC,
>>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC);
>>>> +               regmap_update_bits(i2s->regmap, I2S_CLR,
>>>> +                                  I2S_CLR_TXC,
>>>> +                                  I2S_CLR_TXC);
>>>>
>>>> -                       regmap_read(i2s->regmap, I2S_CLR, &val);
>>>> +               regmap_read(i2s->regmap, I2S_CLR, &val);
>>>>
>>>> -                       /* Should wait for clear operation to finish */
>>>> -                       while (val) {
>>>> -                               regmap_read(i2s->regmap, I2S_CLR, &val);
>>>> -                               retry--;
>>>> -                               if (!retry) {
>>>> -                                       dev_warn(i2s->dev, "fail to
>>>> clear\n");
>>>> -                                       break;
>>>> -                               }
>>>> +               /* Should wait for clear operation to finish */
>>>> +               while (val & I2S_CLR_TXC) {
>>>> +                       regmap_read(i2s->regmap, I2S_CLR, &val);
>>>> +                       retry--;
>>>> +                       if (!retry) {
>>>> +                               dev_warn(i2s->dev, "fail to clear\n");
>>>> +                               break;
>>>>                          }
>>>>                  }
>>>>          }
>>>> @@ -128,8 +124,8 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev
>>>> *i2s, int on)
>>>>                                     I2S_DMACR_RDE_ENABLE,
>>>> I2S_DMACR_RDE_ENABLE);
>>>>
>>>>                  regmap_update_bits(i2s->regmap, I2S_XFER,
>>>> -                                  I2S_XFER_TXS_START |
>>>> I2S_XFER_RXS_START,
>>>> -                                  I2S_XFER_TXS_START |
>>>> I2S_XFER_RXS_START);
>>>> +                                  I2S_XFER_RXS_START,
>>>> +                                  I2S_XFER_RXS_START);
>>>>
>>>>                  i2s->rx_start = true;
>>>>          } else {
>>>> @@ -138,27 +134,23 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev
>>>> *i2s, int on)
>>>>                  regmap_update_bits(i2s->regmap, I2S_DMACR,
>>>>                                     I2S_DMACR_RDE_ENABLE,
>>>> I2S_DMACR_RDE_DISABLE);
>>>>
>>>> -               if (!i2s->tx_start) {
>>>> -                       regmap_update_bits(i2s->regmap, I2S_XFER,
>>>> -                                          I2S_XFER_TXS_START |
>>>> -                                          I2S_XFER_RXS_START,
>>>> -                                          I2S_XFER_TXS_STOP |
>>>> -                                          I2S_XFER_RXS_STOP);
>>>> +               regmap_update_bits(i2s->regmap, I2S_XFER,
>>>> +                                  I2S_XFER_RXS_START,
>>>> +                                  I2S_XFER_RXS_STOP);
>>>>
>>>> -                       regmap_update_bits(i2s->regmap, I2S_CLR,
>>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC,
>>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC);
>>>> +               regmap_update_bits(i2s->regmap, I2S_CLR,
>>>> +                                  I2S_CLR_RXC,
>>>> +                                  I2S_CLR_RXC);
>>>>
>>>> -                       regmap_read(i2s->regmap, I2S_CLR, &val);
>>>> +               regmap_read(i2s->regmap, I2S_CLR, &val);
>>>>
>>>> -                       /* Should wait for clear operation to finish */
>>>> -                       while (val) {
>>>> -                               regmap_read(i2s->regmap, I2S_CLR, &val);
>>>> -                               retry--;
>>>> -                               if (!retry) {
>>>> -                                       dev_warn(i2s->dev, "fail to
>>>> clear\n");
>>>> -                                       break;
>>>> -                               }
>>>> +               /* Should wait for clear operation to finish */
>>>> +               while (val & I2S_CLR_RXC) {
>>>> +                       regmap_read(i2s->regmap, I2S_CLR, &val);
>>>> +                       retry--;
>>>> +                       if (!retry) {
>>>> +                               dev_warn(i2s->dev, "fail to clear\n");
>>>> +                               break;
>>>>                          }
>>>>                  }
>>>>          }
>>>> --
>>>> 2.6.3.462.gbe2c914
>>>
>>>
>>> Using my Veyron Jerry Chromebook wiht latest kernel I found that the
>>> speakers doesn't work. Bisect points to this patch as the offending
>>> commit. However your changes looks reasonable the fact is that
>>> reverting the patch makes the audio work again on my device. I need to
>>> dig a bit more into the issue, but meanwhile, any idea on what is
>>> happening ? Can I ask which device did you test?
>>
>>
>> I tested this on a Radxa Rock2 square.  This change fixed an issue I
>> found when running separate processes for playback and recording (I was
>> testing with arecord and speaker-test IIRC) but I don't think that
>> should be relevant.  I just read through the patch again and I can't see
>> anything obviously wrong so I'm afraid I don't have any idea what's
>> causing the problem you're seeing.
>>
> Do you have test playback/capture at the same time? I think you may
> reproduce this issue if you do as follows:
>
> step 1: tinyplay test.wav -D 0 -d 0 -p 1024 -n 4 &
> step 2: tinycap r.wav -D 0 -d 0 -p 1024 -n 4 &
>
> you will find that there is no music now.
>
> because of this problem, we enable tx/rx at the same time to WA this issue.
>

I can confirm that reverting John's patch audio playback/capture at
the same time works on my Veyron Jerry Chromebook.

> May I know what's the issue that you met before?
>>
>>
>> John
>>
>> _______________________________________________
>> Linux-rockchip mailing list
>> Linux-rockchip at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>>
>>
>>
>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel


From caesar.upstream at gmail.com  Tue May  3 02:25:47 2016
From: caesar.upstream at gmail.com (Caesar Wang)
Date: Tue, 3 May 2016 17:25:47 +0800
Subject: [PATCH 1/4] thermal: Add support for hardware-tracked trip points
In-Reply-To: <20160427214843.GA6438@localhost.localdomain>
References: <1461553367-24744-1-git-send-email-wxt@rock-chips.com>
 <1461553367-24744-2-git-send-email-wxt@rock-chips.com>
 <20160427214843.GA6438@localhost.localdomain>
Message-ID: <57286E9B.5060804@gmail.com>



? 2016?04?28? 05:48, Eduardo Valentin ??:
> This patch is based on an earlier version from Mikko Perttunen
> <mikko.perttunen at kapsi.fi>
>
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Zhang Rui <rui.zhang at intel.com>
> Cc: Eduardo Valentin <edubezval at gmail.com>
> Cc: linux-pm at vger.kernel.org
> ---
>
>   drivers/thermal/thermal_core.c | 48 ++++++++++++++++++++++++++++++++++++++++++
>   include/linux/thermal.h        |  3 +++
>>
>
>   static void update_temperature(struct thermal_zone_device *tz)
>   {
>   	int temp, ret;
> @@ -569,6 +610,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
>   
>   	update_temperature(tz);
>   
> +	thermal_zone_set_trips(tz);
> +
>   	for (count = 0; count < tz->trips; count++)
>   		handle_thermal_trip(tz, count);
>   }
> @@ -754,6 +797,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
>   	 */
>   	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
>   
> +	if (!ret)
> +		thermal_zone_set_trips(tz);
> +
> You would probably want to do the same on trip_point_temp_store().
>

Sorry, that has been set in thermal_zone_device_update().

static ssize_t trip_point_temp_store()
{
     ..
     thermal_zone_device_update(tz);
     ..
}

> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip


-- 
Thanks,
Caesar



From wxt at rock-chips.com  Tue May  3 02:33:28 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Tue,  3 May 2016 17:33:28 +0800
Subject: [PATCH v2 0/5] Thermal: Support for hardware-tracked trip points
Message-ID: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>

The history patches come from Mikko and Sascha.
http://thread.gmane.org/gmane.linux.power-management.general/59451

Now, I pick them up to continue upstream.
Nevermind!

This series history patches:
v1: https://lkml.org/lkml/2016/4/24/227

This series adds support for hardware trip points. It picks up earlier
work from Mikko Perttunen. Mikko implemented hardware trip points as part
of the device tree support. It was suggested back then to move the
functionality to the thermal core instead of putting more code into the
device tree support. This series does exactly that.

This series patches rebase the conflicts.
Note that the hardware-tracked trip points are very well tested currently.

Verified and tested on https://github.com/Caesar-github/rockchip/tree/wip/fixes-thermal-0503
That's based on linux-kernel 20160502.
.Linux version 4.6.0-rc6-next-20160502-08922-g860ed34 (wxt at nb)


Changes in v2:
- update the sysfs-api.txt for set_trips
- add the commit in patch[v2 2/5].
- Update the commit for patch[v2 4/5].

Caesar Wang (1):
  thermal: rockchip: add the set_trips function

Sascha Hauer (4):
  thermal: Add support for hardware-tracked trip points
  thermal: of: implement .set_trips for device tree thermal zones
  thermal: streamline get_trend callbacks
  thermal: bang-bang governor: act on lower trip boundary

 Documentation/thermal/sysfs-api.txt                |  7 +++
 drivers/thermal/gov_bang_bang.c                    |  2 +-
 drivers/thermal/of-thermal.c                       | 23 +++++-----
 drivers/thermal/rockchip_thermal.c                 | 39 ++++++++++++++++
 drivers/thermal/thermal_core.c                     | 52 ++++++++++++++++++++++
 drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 25 ++++-------
 include/linux/thermal.h                            |  9 +++-
 7 files changed, 128 insertions(+), 29 deletions(-)

-- 
1.9.1



From wxt at rock-chips.com  Tue May  3 02:33:29 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Tue,  3 May 2016 17:33:29 +0800
Subject: [PATCH v2 1/5] thermal: Add support for hardware-tracked trip points
In-Reply-To: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1462268013-14992-2-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

This adds support for hardware-tracked trip points to the device tree
thermal sensor framework.

The framework supports an arbitrary number of trip points. Whenever
the current temperature is updated, the trip points immediately
below and above the current temperature are found. A .set_trips
callback is then called with the temperatures. If there is no trip
point above or below the current temperature, the passed trip
temperature will be -INT_MAX or INT_MAX respectively. In this callback,
the driver should program the hardware such that it is notified
when either of these trip points are triggered. When a trip point
is triggered, the driver should call `thermal_zone_device_update'
for the respective thermal zone. This will cause the trip points
to be updated again.

If .set_trips is not implemented, the framework behaves as before.

This patch is based on an earlier version from Mikko Perttunen
<mikko.perttunen at kapsi.fi>

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org

---

Changes in v2:
- update the sysfs-api.txt for set_trips

 Documentation/thermal/sysfs-api.txt |  7 +++++
 drivers/thermal/thermal_core.c      | 52 +++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h             |  3 +++
 3 files changed, 62 insertions(+)

diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index efc3f3d..75d8838 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -49,6 +49,9 @@ temperature) and throttle appropriate devices.
 	.bind: bind the thermal zone device with a thermal cooling device.
 	.unbind: unbind the thermal zone device with a thermal cooling device.
 	.get_temp: get the current temperature of the thermal zone.
+	.set_trips: set the trip points window. Whenever the current temperature
+		    is updated, the trip points immediately below and above the
+		    current temperature are found.
 	.get_mode: get the current mode (enabled/disabled) of the thermal zone.
 	    - "enabled" means the kernel thermal management is enabled.
 	    - "disabled" will prevent kernel thermal driver action upon trip points
@@ -95,6 +98,10 @@ temperature) and throttle appropriate devices.
 			get_temp:	a pointer to a function that reads the
 					sensor temperature. This is mandatory
 					callback provided by sensor driver.
+			set_trips:      a pointer to a function that sets a
+					temperature window. When this window is
+					left the driver must inform the thermal
+					core via thermal_zone_device_update.
 			get_trend: 	a pointer to a function that reads the
 					sensor temperature trend.
 			set_emul_temp:	a pointer to a function that sets
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 5133cd1..e5bfbd3 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -520,6 +520,51 @@ exit:
 }
 EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
 
+static void thermal_zone_set_trips(struct thermal_zone_device *tz)
+{
+	int low = -INT_MAX;
+	int high = INT_MAX;
+	int trip_temp, hysteresis;
+	int temp = tz->temperature;
+	int i, ret;
+
+	if (!tz->ops->set_trips)
+		return;
+
+	for (i = 0; i < tz->trips; i++) {
+		int trip_low;
+
+		tz->ops->get_trip_temp(tz, i, &trip_temp);
+		tz->ops->get_trip_hyst(tz, i, &hysteresis);
+
+		trip_low = trip_temp - hysteresis;
+
+		if (trip_low < temp && trip_low > low)
+			low = trip_low;
+
+		if (trip_temp > temp && trip_temp < high)
+			high = trip_temp;
+	}
+
+	/* No need to change trip points */
+	if (tz->prev_low_trip == low && tz->prev_high_trip == high)
+		return;
+
+	tz->prev_low_trip = low;
+	tz->prev_high_trip = high;
+
+	dev_dbg(&tz->device, "new temperature boundaries: %d < x < %d\n",
+			low, high);
+
+	/*
+	 * Set a temperature window. When this window is left the driver
+	 * must inform the thermal core via thermal_zone_device_update.
+	 */
+	ret = tz->ops->set_trips(tz, low, high);
+	if (ret)
+		dev_err(&tz->device, "Failed to set trips: %d\n", ret);
+}
+
 static void update_temperature(struct thermal_zone_device *tz)
 {
 	int temp, ret;
@@ -569,6 +614,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
 
 	update_temperature(tz);
 
+	thermal_zone_set_trips(tz);
+
 	for (count = 0; count < tz->trips; count++)
 		handle_thermal_trip(tz, count);
 }
@@ -754,6 +801,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
 	 */
 	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
 
+	if (!ret)
+		thermal_zone_set_trips(tz);
+
 	return ret ? ret : count;
 }
 
@@ -1843,6 +1893,8 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
 	tz->trips = trips;
 	tz->passive_delay = passive_delay;
 	tz->polling_delay = polling_delay;
+	tz->prev_low_trip = INT_MAX;
+	tz->prev_high_trip = -INT_MAX;
 	/* A new thermal zone needs to be updated anyway. */
 	atomic_set(&tz->need_update, 1);
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index e45abe7..e258359 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -98,6 +98,7 @@ struct thermal_zone_device_ops {
 	int (*unbind) (struct thermal_zone_device *,
 		       struct thermal_cooling_device *);
 	int (*get_temp) (struct thermal_zone_device *, int *);
+	int (*set_trips) (struct thermal_zone_device *, int, int);
 	int (*get_mode) (struct thermal_zone_device *,
 			 enum thermal_device_mode *);
 	int (*set_mode) (struct thermal_zone_device *,
@@ -199,6 +200,8 @@ struct thermal_zone_device {
 	int last_temperature;
 	int emul_temperature;
 	int passive;
+	int prev_low_trip;
+	int prev_high_trip;
 	unsigned int forced_passive;
 	atomic_t need_update;
 	struct thermal_zone_device_ops *ops;
-- 
1.9.1



From wxt at rock-chips.com  Tue May  3 02:33:30 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Tue,  3 May 2016 17:33:30 +0800
Subject: [PATCH v2 2/5] thermal: of: implement .set_trips for device tree
 thermal zones
In-Reply-To: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1462268013-14992-3-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

This patch implemnets .set_trips for device tree thermal zones.
As the hardware-tracked trip points is supported by thermal core patch[0].

patch[0]
"thermal: Add support for hardware-tracked trip points".

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org

---

Changes in v2:
- add the commit in patch[v2 2/5].

 drivers/thermal/of-thermal.c | 12 ++++++++++++
 include/linux/thermal.h      |  4 ++++
 2 files changed, 16 insertions(+)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index b8e509c..8722e63 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -101,6 +101,17 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
 	return data->ops->get_temp(data->sensor_data, temp);
 }
 
+static int of_thermal_set_trips(struct thermal_zone_device *tz,
+				int low, int high)
+{
+	struct __thermal_zone *data = tz->devdata;
+
+	if (!data->ops || !data->ops->set_trips)
+		return -EINVAL;
+
+	return data->ops->set_trips(data->sensor_data, low, high);
+}
+
 /**
  * of_thermal_get_ntrips - function to export number of available trip
  *			   points.
@@ -427,6 +438,7 @@ thermal_zone_of_add_sensor(struct device_node *zone,
 
 	tzd->ops->get_temp = of_thermal_get_temp;
 	tzd->ops->get_trend = of_thermal_get_trend;
+	tzd->ops->set_trips = of_thermal_set_trips;
 	tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
 	mutex_unlock(&tzd->lock);
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index e258359..09053eb 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -336,12 +336,16 @@ struct thermal_genl_event {
  *
  * Optional:
  * @get_trend: a pointer to a function that reads the sensor temperature trend.
+ * @set_trips: a pointer to a function that sets a temperature window. When
+ *	       this window is left the driver must inform the thermal core via
+ *	       thermal_zone_device_update.
  * @set_emul_temp: a pointer to a function that sets sensor emulated
  *		   temperature.
  */
 struct thermal_zone_of_device_ops {
 	int (*get_temp)(void *, int *);
 	int (*get_trend)(void *, long *);
+	int (*set_trips)(void *, int, int);
 	int (*set_emul_temp)(void *, int);
 	int (*set_trip_temp)(void *, int, int);
 };
-- 
1.9.1



From wxt at rock-chips.com  Tue May  3 02:33:31 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Tue,  3 May 2016 17:33:31 +0800
Subject: [PATCH v2 3/5] thermal: streamline get_trend callbacks
In-Reply-To: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1462268013-14992-4-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

The .get_trend callback in struct thermal_zone_device_ops has
the prototype:
        int (*get_trend) (struct thermal_zone_device *, int,
                          enum thermal_trend *);
whereas the .get_trend callback in struct thermal_zone_of_device_ops
has:
        int (*get_trend)(void *, long *);

Streamline both prototypes and add the trip argument to the OF callback
aswell and use enum thermal_trend * instead of an integer pointer.

While the OF prototype may be the better one, this should be decided at
framework level and not on OF level.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org
---

Changes in v2: None

 drivers/thermal/of-thermal.c                       | 11 +---------
 drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 25 +++++++---------------
 include/linux/thermal.h                            |  2 +-
 3 files changed, 10 insertions(+), 28 deletions(-)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 8722e63..13833d9 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -202,24 +202,15 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
 				enum thermal_trend *trend)
 {
 	struct __thermal_zone *data = tz->devdata;
-	long dev_trend;
 	int r;
 
 	if (!data->ops->get_trend)
 		return -EINVAL;
 
-	r = data->ops->get_trend(data->sensor_data, &dev_trend);
+	r = data->ops->get_trend(data->sensor_data, trip, trend);
 	if (r)
 		return r;
 
-	/* TODO: These intervals might have some thresholds, but in core code */
-	if (dev_trend > 0)
-		*trend = THERMAL_TREND_RAISING;
-	else if (dev_trend < 0)
-		*trend = THERMAL_TREND_DROPPING;
-	else
-		*trend = THERMAL_TREND_STABLE;
-
 	return 0;
 }
 
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
index 15c0a9a..4a6757c 100644
--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
@@ -239,7 +239,7 @@ static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int __ti_thermal_get_trend(void *p, long *trend)
+static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend)
 {
 	struct ti_thermal_data *data = p;
 	struct ti_bandgap *bgp;
@@ -252,22 +252,6 @@ static int __ti_thermal_get_trend(void *p, long *trend)
 	if (ret)
 		return ret;
 
-	*trend = tr;
-
-	return 0;
-}
-
-/* Get the temperature trend callback functions for thermal zone */
-static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
-				int trip, enum thermal_trend *trend)
-{
-	int ret;
-	long tr;
-
-	ret = __ti_thermal_get_trend(thermal->devdata, &tr);
-	if (ret)
-		return ret;
-
 	if (tr > 0)
 		*trend = THERMAL_TREND_RAISING;
 	else if (tr < 0)
@@ -278,6 +262,13 @@ static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
 	return 0;
 }
 
+/* Get the temperature trend callback functions for thermal zone */
+static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
+				int trip, enum thermal_trend *trend)
+{
+	return __ti_thermal_get_trend(thermal->devdata, trip, trend);
+}
+
 /* Get critical temperature callback functions for thermal zone */
 static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
 				    int *temp)
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 09053eb..37cdd16 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -344,7 +344,7 @@ struct thermal_genl_event {
  */
 struct thermal_zone_of_device_ops {
 	int (*get_temp)(void *, int *);
-	int (*get_trend)(void *, long *);
+	int (*get_trend)(void *, int, enum thermal_trend *);
 	int (*set_trips)(void *, int, int);
 	int (*set_emul_temp)(void *, int);
 	int (*set_trip_temp)(void *, int, int);
-- 
1.9.1



From wxt at rock-chips.com  Tue May  3 02:33:32 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Tue,  3 May 2016 17:33:32 +0800
Subject: [PATCH v2 4/5] thermal: bang-bang governor: act on lower trip boundary
In-Reply-To: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1462268013-14992-5-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

With interrupt driven thermal zones we pass the lower and upper
temperature on which shall be acted, so in the governor we have to act on
the exact lower temperature to be consistent. Otherwise an interrupt maybe
generated on the exact lower temperature, but the bang bang governor does
not react since The polling driven zones have to be one step cooler before
the governor reacts.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org

---

Changes in v2:
- Update the commit for patch[v2 4/5].

 drivers/thermal/gov_bang_bang.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
index 70836c5..9d1dfea 100644
--- a/drivers/thermal/gov_bang_bang.c
+++ b/drivers/thermal/gov_bang_bang.c
@@ -59,7 +59,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
 		if (instance->target == 0 && tz->temperature >= trip_temp)
 			instance->target = 1;
 		else if (instance->target == 1 &&
-				tz->temperature < trip_temp - trip_hyst)
+				tz->temperature <= trip_temp - trip_hyst)
 			instance->target = 0;
 
 		dev_dbg(&instance->cdev->device, "target=%d\n",
-- 
1.9.1



From wxt at rock-chips.com  Tue May  3 02:33:33 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Tue,  3 May 2016 17:33:33 +0800
Subject: [PATCH v2 5/5] thermal: rockchip: add the set_trips function
In-Reply-To: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1462268013-14992-6-git-send-email-wxt@rock-chips.com>

Whenever the current temperature is updated, the trip points immediately
below and above the current temperature are found. A sensor driver
callback `set_trips' is then called with the temperatures.
Lastly, The sensor will trigger the hardware high temperature interrupts
to increase the sampleing rate and throttle frequency to limit the
temperature rising When performing passive cooling.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org

---

Changes in v2: None

 drivers/thermal/rockchip_thermal.c | 39 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index 5d491f1..8175cdb 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -96,6 +96,7 @@ struct chip_tsadc_table {
  * @initialize: SoC special initialize tsadc controller method
  * @irq_ack: clear the interrupt
  * @get_temp: get the temperature
+ * @set_alarm_temp: set the high temperature interrupt
  * @set_tshut_temp: set the hardware-controlled shutdown temperature
  * @set_tshut_mode: set the hardware-controlled shutdown mode
  * @table: the chip-specific conversion table
@@ -119,6 +120,8 @@ struct rockchip_tsadc_chip {
 	/* Per-sensor methods */
 	int (*get_temp)(struct chip_tsadc_table table,
 			int chn, void __iomem *reg, int *temp);
+	void (*set_alarm_temp)(struct chip_tsadc_table table,
+			       int chn, void __iomem *reg, int temp);
 	void (*set_tshut_temp)(struct chip_tsadc_table table,
 			       int chn, void __iomem *reg, int temp);
 	void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
@@ -183,6 +186,7 @@ struct rockchip_thermal_data {
 #define TSADCV2_INT_EN				0x08
 #define TSADCV2_INT_PD				0x0c
 #define TSADCV2_DATA(chn)			(0x20 + (chn) * 0x04)
+#define TSADCV2_COMP_INT(chn)		        (0x30 + (chn) * 0x04)
 #define TSADCV2_COMP_SHUT(chn)		        (0x40 + (chn) * 0x04)
 #define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
 #define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
@@ -628,6 +632,20 @@ static int rk_tsadcv2_get_temp(struct chip_tsadc_table table,
 	return rk_tsadcv2_code_to_temp(table, val, temp);
 }
 
+static void rk_tsadcv2_alarm_temp(struct chip_tsadc_table table,
+				  int chn, void __iomem *regs, int temp)
+{
+	u32 alarm_value, int_en;
+
+	alarm_value = rk_tsadcv2_temp_to_code(table, temp);
+	writel_relaxed(alarm_value & table.data_mask,
+		       regs + TSADCV2_COMP_INT(chn));
+
+	int_en = readl_relaxed(regs + TSADCV2_INT_EN);
+	int_en |= TSADCV2_INT_SRC_EN(chn);
+	writel_relaxed(int_en, regs + TSADCV2_INT_EN);
+}
+
 static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table,
 				  int chn, void __iomem *regs, int temp)
 {
@@ -670,6 +688,7 @@ static const struct rockchip_tsadc_chip rk3228_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -694,6 +713,7 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
 	.irq_ack = rk_tsadcv2_irq_ack,
 	.control = rk_tsadcv2_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -718,6 +738,7 @@ static const struct rockchip_tsadc_chip rk3366_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -742,6 +763,7 @@ static const struct rockchip_tsadc_chip rk3368_tsadc_data = {
 	.irq_ack = rk_tsadcv2_irq_ack,
 	.control = rk_tsadcv2_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -766,6 +788,7 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -826,6 +849,21 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
+static int rockchip_thermal_set_trips(void *_sensor, int low, int high)
+{
+	struct rockchip_thermal_sensor *sensor = _sensor;
+	struct rockchip_thermal_data *thermal = sensor->thermal;
+	const struct rockchip_tsadc_chip *tsadc = thermal->chip;
+
+	dev_dbg(&thermal->pdev->dev, "%s: sensor %d: low: %d, high %d\n",
+		__func__, sensor->id, low, high);
+
+	tsadc->set_alarm_temp(tsadc->table,
+			      sensor->id, thermal->regs, high);
+
+	return 0;
+}
+
 static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
 {
 	struct rockchip_thermal_sensor *sensor = _sensor;
@@ -843,6 +881,7 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
 
 static const struct thermal_zone_of_device_ops rockchip_of_thermal_ops = {
 	.get_temp = rockchip_thermal_get_temp,
+	.set_trips = rockchip_thermal_set_trips,
 };
 
 static int rockchip_configure_from_dt(struct device *dev,
-- 
1.9.1



From john at metanate.com  Tue May  3 02:43:18 2016
From: john at metanate.com (John Keeping)
Date: Tue, 3 May 2016 10:43:18 +0100
Subject: [alsa-devel] [PATCH 1/2] ASoC: rockchip: i2s: separate capture
 and playback
In-Reply-To: <CAFqH_50D5PQOkpCDefds3Nyktvitoe2Wx=YcXM2POox1ooO=0g@mail.gmail.com>
References: <1449657147-26959-1-git-send-email-john@metanate.com>
 <CAFqH_52C4JKno4uyt54UdWKAJKM4FPGRiQaQQ9_H-Mz1Cr+Hqg@mail.gmail.com>
 <20160430070049.GF14612@serenity.lan>
 <57282532.7000402@rock-chips.com>
 <CAFqH_50D5PQOkpCDefds3Nyktvitoe2Wx=YcXM2POox1ooO=0g@mail.gmail.com>
Message-ID: <20160503104318.62739a91.john@metanate.com>

Hi Enric,

On Tue, 3 May 2016 11:16:58 +0200, Enric Balletbo Serra wrote:
> 2016-05-03 6:12 GMT+02:00 sugar <sugar.zhang at rock-chips.com>:
> > On 4/30/2016 15:00, John Keeping Wrote:  
> >> On Fri, Apr 29, 2016 at 04:59:27PM +0200, Enric Balletbo Serra wrote:  
> >>>
> >>> 2015-12-09 11:32 GMT+01:00 John Keeping <john at metanate.com>:  
> >>>>
> >>>> If we only clear the tx/rx state when both are disabled it is not
> >>>> possible to start/stop one multiple times while the other is running.
> >>>> Since the two are independently controlled, treat them as such and
> >>>> remove the false dependency between capture and playback.
> >>>>
> >>>> Signed-off-by: John Keeping <john at metanate.com>
> >>>> ---
> >>>>   sound/soc/rockchip/rockchip_i2s.c | 72
> >>>> +++++++++++++++++----------------------
> >>>>   1 file changed, 32 insertions(+), 40 deletions(-)
> >>>>
> >>>> diff --git a/sound/soc/rockchip/rockchip_i2s.c
> >>>> b/sound/soc/rockchip/rockchip_i2s.c
> >>>> index 83b1b9c..acc6225 100644
> >>>> --- a/sound/soc/rockchip/rockchip_i2s.c
> >>>> +++ b/sound/soc/rockchip/rockchip_i2s.c
> >>>> @@ -82,8 +82,8 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev
> >>>> *i2s, int on)
> >>>>                                     I2S_DMACR_TDE_ENABLE,
> >>>> I2S_DMACR_TDE_ENABLE);
> >>>>
> >>>>                  regmap_update_bits(i2s->regmap, I2S_XFER,
> >>>> -                                  I2S_XFER_TXS_START |
> >>>> I2S_XFER_RXS_START,
> >>>> -                                  I2S_XFER_TXS_START |
> >>>> I2S_XFER_RXS_START);
> >>>> +                                  I2S_XFER_TXS_START,
> >>>> +                                  I2S_XFER_TXS_START);
> >>>>
> >>>>                  i2s->tx_start = true;
> >>>>          } else {
> >>>> @@ -92,27 +92,23 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev
> >>>> *i2s, int on)
> >>>>                  regmap_update_bits(i2s->regmap, I2S_DMACR,
> >>>>                                     I2S_DMACR_TDE_ENABLE,
> >>>> I2S_DMACR_TDE_DISABLE);
> >>>>
> >>>> -               if (!i2s->rx_start) {
> >>>> -                       regmap_update_bits(i2s->regmap, I2S_XFER,
> >>>> -                                          I2S_XFER_TXS_START |
> >>>> -                                          I2S_XFER_RXS_START,
> >>>> -                                          I2S_XFER_TXS_STOP |
> >>>> -                                          I2S_XFER_RXS_STOP);
> >>>> +               regmap_update_bits(i2s->regmap, I2S_XFER,
> >>>> +                                  I2S_XFER_TXS_START,
> >>>> +                                  I2S_XFER_TXS_STOP);
> >>>>
> >>>> -                       regmap_update_bits(i2s->regmap, I2S_CLR,
> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC,
> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC);
> >>>> +               regmap_update_bits(i2s->regmap, I2S_CLR,
> >>>> +                                  I2S_CLR_TXC,
> >>>> +                                  I2S_CLR_TXC);
> >>>>
> >>>> -                       regmap_read(i2s->regmap, I2S_CLR, &val);
> >>>> +               regmap_read(i2s->regmap, I2S_CLR, &val);
> >>>>
> >>>> -                       /* Should wait for clear operation to finish */
> >>>> -                       while (val) {
> >>>> -                               regmap_read(i2s->regmap, I2S_CLR, &val);
> >>>> -                               retry--;
> >>>> -                               if (!retry) {
> >>>> -                                       dev_warn(i2s->dev, "fail to
> >>>> clear\n");
> >>>> -                                       break;
> >>>> -                               }
> >>>> +               /* Should wait for clear operation to finish */
> >>>> +               while (val & I2S_CLR_TXC) {
> >>>> +                       regmap_read(i2s->regmap, I2S_CLR, &val);
> >>>> +                       retry--;
> >>>> +                       if (!retry) {
> >>>> +                               dev_warn(i2s->dev, "fail to clear\n");
> >>>> +                               break;
> >>>>                          }
> >>>>                  }
> >>>>          }
> >>>> @@ -128,8 +124,8 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev
> >>>> *i2s, int on)
> >>>>                                     I2S_DMACR_RDE_ENABLE,
> >>>> I2S_DMACR_RDE_ENABLE);
> >>>>
> >>>>                  regmap_update_bits(i2s->regmap, I2S_XFER,
> >>>> -                                  I2S_XFER_TXS_START |
> >>>> I2S_XFER_RXS_START,
> >>>> -                                  I2S_XFER_TXS_START |
> >>>> I2S_XFER_RXS_START);
> >>>> +                                  I2S_XFER_RXS_START,
> >>>> +                                  I2S_XFER_RXS_START);
> >>>>
> >>>>                  i2s->rx_start = true;
> >>>>          } else {
> >>>> @@ -138,27 +134,23 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev
> >>>> *i2s, int on)
> >>>>                  regmap_update_bits(i2s->regmap, I2S_DMACR,
> >>>>                                     I2S_DMACR_RDE_ENABLE,
> >>>> I2S_DMACR_RDE_DISABLE);
> >>>>
> >>>> -               if (!i2s->tx_start) {
> >>>> -                       regmap_update_bits(i2s->regmap, I2S_XFER,
> >>>> -                                          I2S_XFER_TXS_START |
> >>>> -                                          I2S_XFER_RXS_START,
> >>>> -                                          I2S_XFER_TXS_STOP |
> >>>> -                                          I2S_XFER_RXS_STOP);
> >>>> +               regmap_update_bits(i2s->regmap, I2S_XFER,
> >>>> +                                  I2S_XFER_RXS_START,
> >>>> +                                  I2S_XFER_RXS_STOP);
> >>>>
> >>>> -                       regmap_update_bits(i2s->regmap, I2S_CLR,
> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC,
> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC);
> >>>> +               regmap_update_bits(i2s->regmap, I2S_CLR,
> >>>> +                                  I2S_CLR_RXC,
> >>>> +                                  I2S_CLR_RXC);
> >>>>
> >>>> -                       regmap_read(i2s->regmap, I2S_CLR, &val);
> >>>> +               regmap_read(i2s->regmap, I2S_CLR, &val);
> >>>>
> >>>> -                       /* Should wait for clear operation to finish */
> >>>> -                       while (val) {
> >>>> -                               regmap_read(i2s->regmap, I2S_CLR, &val);
> >>>> -                               retry--;
> >>>> -                               if (!retry) {
> >>>> -                                       dev_warn(i2s->dev, "fail to
> >>>> clear\n");
> >>>> -                                       break;
> >>>> -                               }
> >>>> +               /* Should wait for clear operation to finish */
> >>>> +               while (val & I2S_CLR_RXC) {
> >>>> +                       regmap_read(i2s->regmap, I2S_CLR, &val);
> >>>> +                       retry--;
> >>>> +                       if (!retry) {
> >>>> +                               dev_warn(i2s->dev, "fail to clear\n");
> >>>> +                               break;
> >>>>                          }
> >>>>                  }
> >>>>          }
> >>>> --
> >>>> 2.6.3.462.gbe2c914  
> >>>
> >>>
> >>> Using my Veyron Jerry Chromebook wiht latest kernel I found that the
> >>> speakers doesn't work. Bisect points to this patch as the offending
> >>> commit. However your changes looks reasonable the fact is that
> >>> reverting the patch makes the audio work again on my device. I need to
> >>> dig a bit more into the issue, but meanwhile, any idea on what is
> >>> happening ? Can I ask which device did you test?  
> >>
> >>
> >> I tested this on a Radxa Rock2 square.  This change fixed an issue I
> >> found when running separate processes for playback and recording (I was
> >> testing with arecord and speaker-test IIRC) but I don't think that
> >> should be relevant.  I just read through the patch again and I can't see
> >> anything obviously wrong so I'm afraid I don't have any idea what's
> >> causing the problem you're seeing.
> >>  
> > Do you have test playback/capture at the same time? I think you may
> > reproduce this issue if you do as follows:
> >
> > step 1: tinyplay test.wav -D 0 -d 0 -p 1024 -n 4 &
> > step 2: tinycap r.wav -D 0 -d 0 -p 1024 -n 4 &
> >
> > you will find that there is no music now.
> >
> > because of this problem, we enable tx/rx at the same time to WA this issue.
> >  
> 
> I can confirm that reverting John's patch audio playback/capture at
> the same time works on my Veyron Jerry Chromebook.

Have you tried stopping one of the processes and then starting it again
(without touching the other process)?  That's the case that was broken
for me without this patch.

I have had a quick look through the code I'm using and I noticed that I
have another change that hasn't been sent upstream, which marks the
I2S_FIFOLR register as volatile in rockchip_i2s_volatile_reg():

-- >8 --
Subject: [PATCH] ASoC: rockchip: i2s: mark FIFOLR register volatile

The FIFO levels will be updated by the device so they should not be
cached.

Signed-off-by: John Keeping <john at metanate.com>
---
 sound/soc/rockchip/rockchip_i2s.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index d78f4c925b02..b517d8abcc40 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -434,6 +434,7 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg)
 	switch (reg) {
 	case I2S_INTSR:
 	case I2S_CLR:
+	case I2S_FIFOLR:
 		return true;
 	default:
 		return false;
-- 8< --


Regards,
John


From eballetbo at gmail.com  Tue May  3 03:21:25 2016
From: eballetbo at gmail.com (Enric Balletbo Serra)
Date: Tue, 3 May 2016 12:21:25 +0200
Subject: [alsa-devel] [PATCH 1/2] ASoC: rockchip: i2s: separate capture
 and playback
In-Reply-To: <20160503104318.62739a91.john@metanate.com>
References: <1449657147-26959-1-git-send-email-john@metanate.com>
 <CAFqH_52C4JKno4uyt54UdWKAJKM4FPGRiQaQQ9_H-Mz1Cr+Hqg@mail.gmail.com>
 <20160430070049.GF14612@serenity.lan>
 <57282532.7000402@rock-chips.com>
 <CAFqH_50D5PQOkpCDefds3Nyktvitoe2Wx=YcXM2POox1ooO=0g@mail.gmail.com>
 <20160503104318.62739a91.john@metanate.com>
Message-ID: <CAFqH_518WDfBATtxYSbtPTdrV1MH=Y2UDBQNeCa2xZTiMp54zw@mail.gmail.com>

Hi John,

2016-05-03 11:43 GMT+02:00 John Keeping <john at metanate.com>:
> Hi Enric,
>
> On Tue, 3 May 2016 11:16:58 +0200, Enric Balletbo Serra wrote:
>> 2016-05-03 6:12 GMT+02:00 sugar <sugar.zhang at rock-chips.com>:
>> > On 4/30/2016 15:00, John Keeping Wrote:
>> >> On Fri, Apr 29, 2016 at 04:59:27PM +0200, Enric Balletbo Serra wrote:
>> >>>
>> >>> 2015-12-09 11:32 GMT+01:00 John Keeping <john at metanate.com>:
>> >>>>
>> >>>> If we only clear the tx/rx state when both are disabled it is not
>> >>>> possible to start/stop one multiple times while the other is running.
>> >>>> Since the two are independently controlled, treat them as such and
>> >>>> remove the false dependency between capture and playback.
>> >>>>
>> >>>> Signed-off-by: John Keeping <john at metanate.com>
>> >>>> ---
>> >>>>   sound/soc/rockchip/rockchip_i2s.c | 72
>> >>>> +++++++++++++++++----------------------
>> >>>>   1 file changed, 32 insertions(+), 40 deletions(-)
>> >>>>
>> >>>> diff --git a/sound/soc/rockchip/rockchip_i2s.c
>> >>>> b/sound/soc/rockchip/rockchip_i2s.c
>> >>>> index 83b1b9c..acc6225 100644
>> >>>> --- a/sound/soc/rockchip/rockchip_i2s.c
>> >>>> +++ b/sound/soc/rockchip/rockchip_i2s.c
>> >>>> @@ -82,8 +82,8 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev
>> >>>> *i2s, int on)
>> >>>>                                     I2S_DMACR_TDE_ENABLE,
>> >>>> I2S_DMACR_TDE_ENABLE);
>> >>>>
>> >>>>                  regmap_update_bits(i2s->regmap, I2S_XFER,
>> >>>> -                                  I2S_XFER_TXS_START |
>> >>>> I2S_XFER_RXS_START,
>> >>>> -                                  I2S_XFER_TXS_START |
>> >>>> I2S_XFER_RXS_START);
>> >>>> +                                  I2S_XFER_TXS_START,
>> >>>> +                                  I2S_XFER_TXS_START);
>> >>>>
>> >>>>                  i2s->tx_start = true;
>> >>>>          } else {
>> >>>> @@ -92,27 +92,23 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev
>> >>>> *i2s, int on)
>> >>>>                  regmap_update_bits(i2s->regmap, I2S_DMACR,
>> >>>>                                     I2S_DMACR_TDE_ENABLE,
>> >>>> I2S_DMACR_TDE_DISABLE);
>> >>>>
>> >>>> -               if (!i2s->rx_start) {
>> >>>> -                       regmap_update_bits(i2s->regmap, I2S_XFER,
>> >>>> -                                          I2S_XFER_TXS_START |
>> >>>> -                                          I2S_XFER_RXS_START,
>> >>>> -                                          I2S_XFER_TXS_STOP |
>> >>>> -                                          I2S_XFER_RXS_STOP);
>> >>>> +               regmap_update_bits(i2s->regmap, I2S_XFER,
>> >>>> +                                  I2S_XFER_TXS_START,
>> >>>> +                                  I2S_XFER_TXS_STOP);
>> >>>>
>> >>>> -                       regmap_update_bits(i2s->regmap, I2S_CLR,
>> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC,
>> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC);
>> >>>> +               regmap_update_bits(i2s->regmap, I2S_CLR,
>> >>>> +                                  I2S_CLR_TXC,
>> >>>> +                                  I2S_CLR_TXC);
>> >>>>
>> >>>> -                       regmap_read(i2s->regmap, I2S_CLR, &val);
>> >>>> +               regmap_read(i2s->regmap, I2S_CLR, &val);
>> >>>>
>> >>>> -                       /* Should wait for clear operation to finish */
>> >>>> -                       while (val) {
>> >>>> -                               regmap_read(i2s->regmap, I2S_CLR, &val);
>> >>>> -                               retry--;
>> >>>> -                               if (!retry) {
>> >>>> -                                       dev_warn(i2s->dev, "fail to
>> >>>> clear\n");
>> >>>> -                                       break;
>> >>>> -                               }
>> >>>> +               /* Should wait for clear operation to finish */
>> >>>> +               while (val & I2S_CLR_TXC) {
>> >>>> +                       regmap_read(i2s->regmap, I2S_CLR, &val);
>> >>>> +                       retry--;
>> >>>> +                       if (!retry) {
>> >>>> +                               dev_warn(i2s->dev, "fail to clear\n");
>> >>>> +                               break;
>> >>>>                          }
>> >>>>                  }
>> >>>>          }
>> >>>> @@ -128,8 +124,8 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev
>> >>>> *i2s, int on)
>> >>>>                                     I2S_DMACR_RDE_ENABLE,
>> >>>> I2S_DMACR_RDE_ENABLE);
>> >>>>
>> >>>>                  regmap_update_bits(i2s->regmap, I2S_XFER,
>> >>>> -                                  I2S_XFER_TXS_START |
>> >>>> I2S_XFER_RXS_START,
>> >>>> -                                  I2S_XFER_TXS_START |
>> >>>> I2S_XFER_RXS_START);
>> >>>> +                                  I2S_XFER_RXS_START,
>> >>>> +                                  I2S_XFER_RXS_START);
>> >>>>
>> >>>>                  i2s->rx_start = true;
>> >>>>          } else {
>> >>>> @@ -138,27 +134,23 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev
>> >>>> *i2s, int on)
>> >>>>                  regmap_update_bits(i2s->regmap, I2S_DMACR,
>> >>>>                                     I2S_DMACR_RDE_ENABLE,
>> >>>> I2S_DMACR_RDE_DISABLE);
>> >>>>
>> >>>> -               if (!i2s->tx_start) {
>> >>>> -                       regmap_update_bits(i2s->regmap, I2S_XFER,
>> >>>> -                                          I2S_XFER_TXS_START |
>> >>>> -                                          I2S_XFER_RXS_START,
>> >>>> -                                          I2S_XFER_TXS_STOP |
>> >>>> -                                          I2S_XFER_RXS_STOP);
>> >>>> +               regmap_update_bits(i2s->regmap, I2S_XFER,
>> >>>> +                                  I2S_XFER_RXS_START,
>> >>>> +                                  I2S_XFER_RXS_STOP);
>> >>>>
>> >>>> -                       regmap_update_bits(i2s->regmap, I2S_CLR,
>> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC,
>> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC);
>> >>>> +               regmap_update_bits(i2s->regmap, I2S_CLR,
>> >>>> +                                  I2S_CLR_RXC,
>> >>>> +                                  I2S_CLR_RXC);
>> >>>>
>> >>>> -                       regmap_read(i2s->regmap, I2S_CLR, &val);
>> >>>> +               regmap_read(i2s->regmap, I2S_CLR, &val);
>> >>>>
>> >>>> -                       /* Should wait for clear operation to finish */
>> >>>> -                       while (val) {
>> >>>> -                               regmap_read(i2s->regmap, I2S_CLR, &val);
>> >>>> -                               retry--;
>> >>>> -                               if (!retry) {
>> >>>> -                                       dev_warn(i2s->dev, "fail to
>> >>>> clear\n");
>> >>>> -                                       break;
>> >>>> -                               }
>> >>>> +               /* Should wait for clear operation to finish */
>> >>>> +               while (val & I2S_CLR_RXC) {
>> >>>> +                       regmap_read(i2s->regmap, I2S_CLR, &val);
>> >>>> +                       retry--;
>> >>>> +                       if (!retry) {
>> >>>> +                               dev_warn(i2s->dev, "fail to clear\n");
>> >>>> +                               break;
>> >>>>                          }
>> >>>>                  }
>> >>>>          }
>> >>>> --
>> >>>> 2.6.3.462.gbe2c914
>> >>>
>> >>>
>> >>> Using my Veyron Jerry Chromebook wiht latest kernel I found that the
>> >>> speakers doesn't work. Bisect points to this patch as the offending
>> >>> commit. However your changes looks reasonable the fact is that
>> >>> reverting the patch makes the audio work again on my device. I need to
>> >>> dig a bit more into the issue, but meanwhile, any idea on what is
>> >>> happening ? Can I ask which device did you test?
>> >>
>> >>
>> >> I tested this on a Radxa Rock2 square.  This change fixed an issue I
>> >> found when running separate processes for playback and recording (I was
>> >> testing with arecord and speaker-test IIRC) but I don't think that
>> >> should be relevant.  I just read through the patch again and I can't see
>> >> anything obviously wrong so I'm afraid I don't have any idea what's
>> >> causing the problem you're seeing.
>> >>
>> > Do you have test playback/capture at the same time? I think you may
>> > reproduce this issue if you do as follows:
>> >
>> > step 1: tinyplay test.wav -D 0 -d 0 -p 1024 -n 4 &
>> > step 2: tinycap r.wav -D 0 -d 0 -p 1024 -n 4 &
>> >
>> > you will find that there is no music now.
>> >
>> > because of this problem, we enable tx/rx at the same time to WA this issue.
>> >
>>
>> I can confirm that reverting John's patch audio playback/capture at
>> the same time works on my Veyron Jerry Chromebook.
>
> Have you tried stopping one of the processes and then starting it again
> (without touching the other process)?  That's the case that was broken
> for me without this patch.
>

I  just tried that and it works on my platform. Meanwhile I reproduced
a song I recorded two wavs.

> I have had a quick look through the code I'm using and I noticed that I
> have another change that hasn't been sent upstream, which marks the
> I2S_FIFOLR register as volatile in rockchip_i2s_volatile_reg():
>

Unfortunately that didn't help, I hear nothing from the speakers :(

I have a Radxa Rock2 Square board, by chance, do you have a git tree
containing the patches to enable the i2s sound for radxa so I can
reproduce both here? At least the codec is not upstreamed, I guess.

> -- >8 --
> Subject: [PATCH] ASoC: rockchip: i2s: mark FIFOLR register volatile
>
> The FIFO levels will be updated by the device so they should not be
> cached.
>
> Signed-off-by: John Keeping <john at metanate.com>
> ---
>  sound/soc/rockchip/rockchip_i2s.c | 1 +
>  1 file changed, 1 insertion(+)
>
> diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
> index d78f4c925b02..b517d8abcc40 100644
> --- a/sound/soc/rockchip/rockchip_i2s.c
> +++ b/sound/soc/rockchip/rockchip_i2s.c
> @@ -434,6 +434,7 @@ static bool rockchip_i2s_volatile_reg(struct device *dev, unsigned int reg)
>         switch (reg) {
>         case I2S_INTSR:
>         case I2S_CLR:
> +       case I2S_FIFOLR:
>                 return true;
>         default:
>                 return false;
> -- 8< --
>
>
> Regards,
> John


From john at metanate.com  Tue May  3 03:32:06 2016
From: john at metanate.com (John Keeping)
Date: Tue, 3 May 2016 11:32:06 +0100
Subject: [alsa-devel] [PATCH 1/2] ASoC: rockchip: i2s: separate capture
 and playback
In-Reply-To: <CAFqH_518WDfBATtxYSbtPTdrV1MH=Y2UDBQNeCa2xZTiMp54zw@mail.gmail.com>
References: <1449657147-26959-1-git-send-email-john@metanate.com>
 <CAFqH_52C4JKno4uyt54UdWKAJKM4FPGRiQaQQ9_H-Mz1Cr+Hqg@mail.gmail.com>
 <20160430070049.GF14612@serenity.lan>
 <57282532.7000402@rock-chips.com>
 <CAFqH_50D5PQOkpCDefds3Nyktvitoe2Wx=YcXM2POox1ooO=0g@mail.gmail.com>
 <20160503104318.62739a91.john@metanate.com>
 <CAFqH_518WDfBATtxYSbtPTdrV1MH=Y2UDBQNeCa2xZTiMp54zw@mail.gmail.com>
Message-ID: <20160503113206.0d7e3215.john@metanate.com>

Hi Enric,

On Tue, 3 May 2016 12:21:25 +0200, Enric Balletbo Serra wrote:
> 2016-05-03 11:43 GMT+02:00 John Keeping <john at metanate.com>:
> > On Tue, 3 May 2016 11:16:58 +0200, Enric Balletbo Serra wrote:  
> >> 2016-05-03 6:12 GMT+02:00 sugar <sugar.zhang at rock-chips.com>:  
> >> > On 4/30/2016 15:00, John Keeping Wrote:  
> >> >> On Fri, Apr 29, 2016 at 04:59:27PM +0200, Enric Balletbo Serra wrote:  
> >> >>>
> >> >>> 2015-12-09 11:32 GMT+01:00 John Keeping <john at metanate.com>:  
> >> >>>>
> >> >>>> If we only clear the tx/rx state when both are disabled it is not
> >> >>>> possible to start/stop one multiple times while the other is running.
> >> >>>> Since the two are independently controlled, treat them as such and
> >> >>>> remove the false dependency between capture and playback.
> >> >>>>
> >> >>>> Signed-off-by: John Keeping <john at metanate.com>
> >> >>>> ---
> >> >>>>   sound/soc/rockchip/rockchip_i2s.c | 72
> >> >>>> +++++++++++++++++----------------------
> >> >>>>   1 file changed, 32 insertions(+), 40 deletions(-)
> >> >>>>
> >> >>>> diff --git a/sound/soc/rockchip/rockchip_i2s.c
> >> >>>> b/sound/soc/rockchip/rockchip_i2s.c
> >> >>>> index 83b1b9c..acc6225 100644
> >> >>>> --- a/sound/soc/rockchip/rockchip_i2s.c
> >> >>>> +++ b/sound/soc/rockchip/rockchip_i2s.c
> >> >>>> @@ -82,8 +82,8 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev
> >> >>>> *i2s, int on)
> >> >>>>                                     I2S_DMACR_TDE_ENABLE,
> >> >>>> I2S_DMACR_TDE_ENABLE);
> >> >>>>
> >> >>>>                  regmap_update_bits(i2s->regmap, I2S_XFER,
> >> >>>> -                                  I2S_XFER_TXS_START |
> >> >>>> I2S_XFER_RXS_START,
> >> >>>> -                                  I2S_XFER_TXS_START |
> >> >>>> I2S_XFER_RXS_START);
> >> >>>> +                                  I2S_XFER_TXS_START,
> >> >>>> +                                  I2S_XFER_TXS_START);
> >> >>>>
> >> >>>>                  i2s->tx_start = true;
> >> >>>>          } else {
> >> >>>> @@ -92,27 +92,23 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev
> >> >>>> *i2s, int on)
> >> >>>>                  regmap_update_bits(i2s->regmap, I2S_DMACR,
> >> >>>>                                     I2S_DMACR_TDE_ENABLE,
> >> >>>> I2S_DMACR_TDE_DISABLE);
> >> >>>>
> >> >>>> -               if (!i2s->rx_start) {
> >> >>>> -                       regmap_update_bits(i2s->regmap, I2S_XFER,
> >> >>>> -                                          I2S_XFER_TXS_START |
> >> >>>> -                                          I2S_XFER_RXS_START,
> >> >>>> -                                          I2S_XFER_TXS_STOP |
> >> >>>> -                                          I2S_XFER_RXS_STOP);
> >> >>>> +               regmap_update_bits(i2s->regmap, I2S_XFER,
> >> >>>> +                                  I2S_XFER_TXS_START,
> >> >>>> +                                  I2S_XFER_TXS_STOP);
> >> >>>>
> >> >>>> -                       regmap_update_bits(i2s->regmap, I2S_CLR,
> >> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC,
> >> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC);
> >> >>>> +               regmap_update_bits(i2s->regmap, I2S_CLR,
> >> >>>> +                                  I2S_CLR_TXC,
> >> >>>> +                                  I2S_CLR_TXC);
> >> >>>>
> >> >>>> -                       regmap_read(i2s->regmap, I2S_CLR, &val);
> >> >>>> +               regmap_read(i2s->regmap, I2S_CLR, &val);
> >> >>>>
> >> >>>> -                       /* Should wait for clear operation to finish */
> >> >>>> -                       while (val) {
> >> >>>> -                               regmap_read(i2s->regmap, I2S_CLR, &val);
> >> >>>> -                               retry--;
> >> >>>> -                               if (!retry) {
> >> >>>> -                                       dev_warn(i2s->dev, "fail to
> >> >>>> clear\n");
> >> >>>> -                                       break;
> >> >>>> -                               }
> >> >>>> +               /* Should wait for clear operation to finish */
> >> >>>> +               while (val & I2S_CLR_TXC) {
> >> >>>> +                       regmap_read(i2s->regmap, I2S_CLR, &val);
> >> >>>> +                       retry--;
> >> >>>> +                       if (!retry) {
> >> >>>> +                               dev_warn(i2s->dev, "fail to clear\n");
> >> >>>> +                               break;
> >> >>>>                          }
> >> >>>>                  }
> >> >>>>          }
> >> >>>> @@ -128,8 +124,8 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev
> >> >>>> *i2s, int on)
> >> >>>>                                     I2S_DMACR_RDE_ENABLE,
> >> >>>> I2S_DMACR_RDE_ENABLE);
> >> >>>>
> >> >>>>                  regmap_update_bits(i2s->regmap, I2S_XFER,
> >> >>>> -                                  I2S_XFER_TXS_START |
> >> >>>> I2S_XFER_RXS_START,
> >> >>>> -                                  I2S_XFER_TXS_START |
> >> >>>> I2S_XFER_RXS_START);
> >> >>>> +                                  I2S_XFER_RXS_START,
> >> >>>> +                                  I2S_XFER_RXS_START);
> >> >>>>
> >> >>>>                  i2s->rx_start = true;
> >> >>>>          } else {
> >> >>>> @@ -138,27 +134,23 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev
> >> >>>> *i2s, int on)
> >> >>>>                  regmap_update_bits(i2s->regmap, I2S_DMACR,
> >> >>>>                                     I2S_DMACR_RDE_ENABLE,
> >> >>>> I2S_DMACR_RDE_DISABLE);
> >> >>>>
> >> >>>> -               if (!i2s->tx_start) {
> >> >>>> -                       regmap_update_bits(i2s->regmap, I2S_XFER,
> >> >>>> -                                          I2S_XFER_TXS_START |
> >> >>>> -                                          I2S_XFER_RXS_START,
> >> >>>> -                                          I2S_XFER_TXS_STOP |
> >> >>>> -                                          I2S_XFER_RXS_STOP);
> >> >>>> +               regmap_update_bits(i2s->regmap, I2S_XFER,
> >> >>>> +                                  I2S_XFER_RXS_START,
> >> >>>> +                                  I2S_XFER_RXS_STOP);
> >> >>>>
> >> >>>> -                       regmap_update_bits(i2s->regmap, I2S_CLR,
> >> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC,
> >> >>>> -                                          I2S_CLR_TXC | I2S_CLR_RXC);
> >> >>>> +               regmap_update_bits(i2s->regmap, I2S_CLR,
> >> >>>> +                                  I2S_CLR_RXC,
> >> >>>> +                                  I2S_CLR_RXC);
> >> >>>>
> >> >>>> -                       regmap_read(i2s->regmap, I2S_CLR, &val);
> >> >>>> +               regmap_read(i2s->regmap, I2S_CLR, &val);
> >> >>>>
> >> >>>> -                       /* Should wait for clear operation to finish */
> >> >>>> -                       while (val) {
> >> >>>> -                               regmap_read(i2s->regmap, I2S_CLR, &val);
> >> >>>> -                               retry--;
> >> >>>> -                               if (!retry) {
> >> >>>> -                                       dev_warn(i2s->dev, "fail to
> >> >>>> clear\n");
> >> >>>> -                                       break;
> >> >>>> -                               }
> >> >>>> +               /* Should wait for clear operation to finish */
> >> >>>> +               while (val & I2S_CLR_RXC) {
> >> >>>> +                       regmap_read(i2s->regmap, I2S_CLR, &val);
> >> >>>> +                       retry--;
> >> >>>> +                       if (!retry) {
> >> >>>> +                               dev_warn(i2s->dev, "fail to clear\n");
> >> >>>> +                               break;
> >> >>>>                          }
> >> >>>>                  }
> >> >>>>          }
> >> >>>> --
> >> >>>> 2.6.3.462.gbe2c914  
> >> >>>
> >> >>>
> >> >>> Using my Veyron Jerry Chromebook wiht latest kernel I found that the
> >> >>> speakers doesn't work. Bisect points to this patch as the offending
> >> >>> commit. However your changes looks reasonable the fact is that
> >> >>> reverting the patch makes the audio work again on my device. I need to
> >> >>> dig a bit more into the issue, but meanwhile, any idea on what is
> >> >>> happening ? Can I ask which device did you test?  
> >> >>
> >> >>
> >> >> I tested this on a Radxa Rock2 square.  This change fixed an issue I
> >> >> found when running separate processes for playback and recording (I was
> >> >> testing with arecord and speaker-test IIRC) but I don't think that
> >> >> should be relevant.  I just read through the patch again and I can't see
> >> >> anything obviously wrong so I'm afraid I don't have any idea what's
> >> >> causing the problem you're seeing.
> >> >>  
> >> > Do you have test playback/capture at the same time? I think you may
> >> > reproduce this issue if you do as follows:
> >> >
> >> > step 1: tinyplay test.wav -D 0 -d 0 -p 1024 -n 4 &
> >> > step 2: tinycap r.wav -D 0 -d 0 -p 1024 -n 4 &
> >> >
> >> > you will find that there is no music now.
> >> >
> >> > because of this problem, we enable tx/rx at the same time to WA this issue.
> >> >  
> >>
> >> I can confirm that reverting John's patch audio playback/capture at
> >> the same time works on my Veyron Jerry Chromebook.  
> >
> > Have you tried stopping one of the processes and then starting it again
> > (without touching the other process)?  That's the case that was broken
> > for me without this patch.
> >  
> 
> I  just tried that and it works on my platform. Meanwhile I reproduced
> a song I recorded two wavs.
> 
> > I have had a quick look through the code I'm using and I noticed that I
> > have another change that hasn't been sent upstream, which marks the
> > I2S_FIFOLR register as volatile in rockchip_i2s_volatile_reg():
> >  
> 
> Unfortunately that didn't help, I hear nothing from the speakers :(

Yeah, I looked a bit more after sending the previous mail and that
register is never referenced by the driver!

> I have a Radxa Rock2 Square board, by chance, do you have a git tree
> containing the patches to enable the i2s sound for radxa so I can
> reproduce both here? At least the codec is not upstreamed, I guess.

I've just pushed a branch to Github:

    https://github.com/johnkeeping/linux/tree/topic/audio


Regards,
John


From kishon at ti.com  Tue May  3 03:58:35 2016
From: kishon at ti.com (Kishon Vijay Abraham I)
Date: Tue, 3 May 2016 16:28:35 +0530
Subject: [PATCH 1/3] phy: rockchip-usb: should be a child device of the GRF
In-Reply-To: <1879262.vnFSl1oxpJ@diego>
References: <1459431812-6286-1-git-send-email-heiko@sntech.de>
 <1459431812-6286-2-git-send-email-heiko@sntech.de> <2045729.fIbxLc8i6o@diego>
 <1879262.vnFSl1oxpJ@diego>
Message-ID: <5728845B.8070405@ti.com>



On Sunday 01 May 2016 01:37 AM, Heiko St?bner wrote:
> Hi Kishon,
> 
> Am Dienstag, 19. April 2016, 08:13:47 schrieb Heiko St?bner:
>> Hi Kishon.
>>
>> Am Donnerstag, 31. M?rz 2016, 15:43:30 schrieb Heiko Stuebner:
>>> The usb-phy is fully enclosed in the general register files (GRF).
>>> Therefore as seen from the device-tree it shouldn't be a separate
>>> platform-
>>> device but instead a sub-device of the GRF - using the simply-mfd
>>> mechanism.
>>>
>>> As the usb-phy is part of the kernel for some releases now, we keep
>>> the old (and now deprecated) binding for compatibility purposes.
>>>
>>> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
>>
>> could you look into picking this patch up for 4.7?
>>
>> Same principle as for the other phy drivers, but it's already in the kernel
>> for a while, so it gets a fallback for the old binding and can go through
>> the normal way.
>>
>> The other two (devicetree-)patches I would then simply queue for 4.8 myself
>> after you're fine with the driver-side.
> 
> just saw that you already have a tag for 4.7-related phy changes since this 
> afternoon, but no phy pull to Greg on lkml yet.
> 
> So maybe there is still a way for this phy conversion (to be under the 
> Rockchip GRF node) to make it in for 4.7 :-) ?

Looks like I've missed this before sending the pull request. Sorry about that.
Is it okay if the PHY changes also go in 4.8?

-Kishon


From heiko at sntech.de  Tue May  3 04:02:53 2016
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Tue, 03 May 2016 13:02:53 +0200
Subject: [PATCH 1/3] phy: rockchip-usb: should be a child device of the GRF
In-Reply-To: <5728845B.8070405@ti.com>
References: <1459431812-6286-1-git-send-email-heiko@sntech.de>
 <1879262.vnFSl1oxpJ@diego> <5728845B.8070405@ti.com>
Message-ID: <7658149.o0yR5eAPe1@diego>

Hi Kishon,

Am Dienstag, 3. Mai 2016, 16:28:35 schrieb Kishon Vijay Abraham I:
> On Sunday 01 May 2016 01:37 AM, Heiko St?bner wrote:
> > Am Dienstag, 19. April 2016, 08:13:47 schrieb Heiko St?bner:
> >> Am Donnerstag, 31. M?rz 2016, 15:43:30 schrieb Heiko Stuebner:
> >>> The usb-phy is fully enclosed in the general register files (GRF).
> >>> Therefore as seen from the device-tree it shouldn't be a separate
> >>> platform-
> >>> device but instead a sub-device of the GRF - using the simply-mfd
> >>> mechanism.
> >>> 
> >>> As the usb-phy is part of the kernel for some releases now, we keep
> >>> the old (and now deprecated) binding for compatibility purposes.
> >>> 
> >>> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> >> 
> >> could you look into picking this patch up for 4.7?
> >> 
> >> Same principle as for the other phy drivers, but it's already in the
> >> kernel
> >> for a while, so it gets a fallback for the old binding and can go through
> >> the normal way.
> >> 
> >> The other two (devicetree-)patches I would then simply queue for 4.8
> >> myself
> >> after you're fine with the driver-side.
> > 
> > just saw that you already have a tag for 4.7-related phy changes since
> > this
> > afternoon, but no phy pull to Greg on lkml yet.
> > 
> > So maybe there is still a way for this phy conversion (to be under the
> > Rockchip GRF node) to make it in for 4.7 :-) ?
> 
> Looks like I've missed this before sending the pull request. Sorry about
> that. Is it okay if the PHY changes also go in 4.8?

yep, 4.8 is no problem as well. We have the current binding in the kernel for 
so long, that waiting one more kernel release won't be a problem.


Heiko


From robh at kernel.org  Tue May  3 10:05:17 2016
From: robh at kernel.org (Rob Herring)
Date: Tue, 3 May 2016 12:05:17 -0500
Subject: [PATCH v2 1/6] Documentation: mmc: add mmc-hs400-enhanced-strobe
In-Reply-To: <1461897960-28860-1-git-send-email-shawn.lin@rock-chips.com>
References: <1461897751-28810-1-git-send-email-shawn.lin@rock-chips.com>
 <1461897960-28860-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <20160503170517.GA31410@rob-hp-laptop>

On Fri, Apr 29, 2016 at 10:46:00AM +0800, Shawn Lin wrote:
> mmc-hs400-enhanced-strobe is used to claim that the
> host can support hs400 mode with enhanced strobe
> introduced by emmc 5.1 spec.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
> 
> Changes in v2: None
> 
>  Documentation/devicetree/bindings/mmc/mmc.txt | 1 +
>  1 file changed, 1 insertion(+)

Acked-by: Rob Herring <robh at kernel.org>


From tpiepho at kymetacorp.com  Tue May  3 12:17:34 2016
From: tpiepho at kymetacorp.com (Trent Piepho)
Date: Tue, 3 May 2016 19:17:34 +0000
Subject: [PATCH v2 0/4] Patches to allow consistent mmc / mmcblk numbering
 w/ device tree
In-Reply-To: <20160430104832.GJ19428@n2100.arm.linux.org.uk>
References: <20160429195741.GY19428@n2100.arm.linux.org.uk>
 <CAD=FV=UGyi0r3kDmc1cpcANTP-2u+7UEgW3r9kRvF2f8qcWH+g@mail.gmail.com>
 <20160429211328.GZ19428@n2100.arm.linux.org.uk>
 <CAD=FV=V8BOsO36eUOGAcXp04xCiN13UGG0Vaf2yhh1MQn85FjA@mail.gmail.com>
 <20160429212920.GA19428@n2100.arm.linux.org.uk>
 <CAD=FV=V9V8P=d59RX1eaAdVxJgMxub1F6hzQNw1QW+7t=3POBw@mail.gmail.com>
 <20160429215017.GC19428@n2100.arm.linux.org.uk>
 <CAD=FV=VgQX_EVhUUCugzv+CZqjzTS8LwyeU5419aX9FbDnWJDg@mail.gmail.com>
 <20160429221606.GE19428@n2100.arm.linux.org.uk>
 <CABxcv==4C+RrEV1Fd+DkbMdGrLyObw36vsmo3wTGdxO=UnAa8w@mail.gmail.com>
 <20160430104832.GJ19428@n2100.arm.linux.org.uk>
Message-ID: <1462303111.9103.225.camel@rtred1test09.kymeta.local>

On Sat, 2016-04-30 at 11:48 +0100, Russell King - ARM Linux wrote:
> On Fri, Apr 29, 2016 at 06:42:35PM -0400, Javier Martinez Canillas wrote:
> > Maybe a third opinion could make this conversation constructive again.

And maybe a forth.

> > I think Doug's point is that using a UUID or labels for consistency is
> > orthogonal to having a deterministic numbering for MMC devices. And I
> > agree with his point of view for what is worth.
> 
> Yes, it may be orthogonal, but there are two issues here:
> 
> 1. How does the system know which MMC device to mount for its rootfs.
> 
> This is the point that I've picked up on, which has been solved for
> years, and actually pre-dates MMC support in the kernel, and that is
> mount by UUID.

What about eMMC boot blocks and replay protected memory block?  These
are special sub-device like features of eMMC that provide storage from
different areas than the normal flash.  The kernel names them something
like "/dev/mmcblk0boot0" and "/dev/mmcblk1rpmb".

They typically don't have partition tables and in fact the kernel
xplicitly does not scan them for a partition table.  So how can they
have a UUID?

Suppose your device has two SD slots, neither with an SD card inserted
in it, one external and one internal behind a locked access panel.  They
serve different purposes.  How do you determine which is which via UUID
when they have no media?

> The kernel itself has no support for mount-by-label, which is normally
> solved by using an initramfs, which contains programs such as mount
> etc which will scan the block devices looking for an appropriately
> labelled filesystem.  Label has slightly more issues since its possible

But what is faster, using an initramfs that loads a working userspace
into RAM, scans the flash device for partition labels, determines the
device ID, and then switches to the real rootfs.  Or having the
bootloader, which already knows the partition the rootfs is in, tell the
kernel what device to mount from the beginning?

Which brings me to another reason for providing device enumeration
information via the device tree that isn't just about mounting the root
filesystem.

The bootloader will create an enumeration of devices so that it can
access them.  The kernel will also create an enumeration of the same
devices.  Should these enumerations be the same, or should they be
different?

Clearly there are advantages to the enumeration being the same.  It's
easier on users if device IDs can be the same between the two
environments, bootloader and kernel, the device can be accessed from.

It also makes it easier if information about a device needs to be passed
from the bootloader to the kernel.  This could be the root filesystem,
but that's not the only thing.  Console serial port is another.  But we
could also want to kernel to know which of the SoC's ports is connected
to the blank eMMC chip it should create a partition table on and format,
and which is connected to the SD card it should store logging data to.

I can't think of any advantage of the enumerations being different.

So if identical enumerations are desirable, how to achieve it?

One way would be to have the bootloader create its enumeration and then
throw it away when the kernel boots.  The the kernel creates a new
enumeration from scratch, using a different system with different code
and a different design, that happens to create the same enumeration that
the bootloader did.  This seems like a bad design to me.  Two different
code bases will need to kept in sync, to always to the same thing in a
different way.  It will be hard to avoid bugs from corner cases that
fail to produce the same enumerations.

Another way would be to have the bootloader tell the kernel what it
enumerated and then have the kernel use this enumeration.  This avoids
the need to keep two code bases in sync.  It avoids bugs where they fail
to produce the same enumeration.

And how to do this pass the enumeration from the bootloader to the
kernel?  The same way all other information from the bootloader is
passed to the kernel, via the device tree.

The alias system that already exists allows the bootloader to tell the
kernel about enumerations it has already created, which it must do since
it runs before the kernel, and would like the kernel to continue to use.

So this isn't just about finding the root filesystem.  It's about
passing enumeration information from the bootloader to the kernel.


From andrew at lunn.ch  Tue May  3 18:32:12 2016
From: andrew at lunn.ch (Andrew Lunn)
Date: Wed, 4 May 2016 03:32:12 +0200
Subject: [PATCH 02/12] eeprom: at24: remove nvmem regmap dependency
In-Reply-To: <20160502073254.GA2015@tetsubishi>
References: <1461526096-29584-1-git-send-email-srinivas.kandagatla@linaro.org>
 <1461526096-29584-3-git-send-email-srinivas.kandagatla@linaro.org>
 <20160502073254.GA2015@tetsubishi>
Message-ID: <20160504013212.GA7972@lunn.ch>

On Mon, May 02, 2016 at 09:32:54AM +0200, Wolfram Sang wrote:
> On Sun, Apr 24, 2016 at 08:28:06PM +0100, Srinivas Kandagatla wrote:
> > This patch moves to nvmem support in the driver to use callback instead
> > of regmap.
> > 
> > Signed-off-by: Srinivas Kandagatla <srinivas.kandagatla at linaro.org>
> 
> Andrew, since you did the NVMEM implementation, could you have a look at
> this? That would be awesome. Thanks!
> 
> > ---
> >  drivers/misc/eeprom/Kconfig |   1 -
> >  drivers/misc/eeprom/at24.c  | 103 ++++++++++----------------------------------
> >  2 files changed, 22 insertions(+), 82 deletions(-)
> > 
> > diff --git a/drivers/misc/eeprom/Kconfig b/drivers/misc/eeprom/Kconfig
> > index cfc493c..2d70464 100644
> > --- a/drivers/misc/eeprom/Kconfig
> > +++ b/drivers/misc/eeprom/Kconfig
> > @@ -3,7 +3,6 @@ menu "EEPROM support"
> >  config EEPROM_AT24
> >  	tristate "I2C EEPROMs / RAMs / ROMs from most vendors"
> >  	depends on I2C && SYSFS
> > -	select REGMAP
> >  	select NVMEM
> >  	help
> >  	  Enable this driver to get read/write support to most I2C EEPROMs
> > diff --git a/drivers/misc/eeprom/at24.c b/drivers/misc/eeprom/at24.c
> > index 089d694..de550a6 100644
> > --- a/drivers/misc/eeprom/at24.c
> > +++ b/drivers/misc/eeprom/at24.c
> > @@ -23,7 +23,6 @@
> >  #include <linux/acpi.h>
> >  #include <linux/i2c.h>
> >  #include <linux/nvmem-provider.h>
> > -#include <linux/regmap.h>
> >  #include <linux/platform_data/at24.h>
> >  
> >  /*
> > @@ -69,7 +68,6 @@ struct at24_data {
> >  	unsigned write_max;
> >  	unsigned num_addresses;
> >  
> > -	struct regmap_config regmap_config;
> >  	struct nvmem_config nvmem_config;
> >  	struct nvmem_device *nvmem;
> >  
> > @@ -252,10 +250,10 @@ static ssize_t at24_eeprom_read(struct at24_data *at24, char *buf,
> >  	return -ETIMEDOUT;
> >  }
> >  
> > -static ssize_t at24_read(struct at24_data *at24,
> > -		char *buf, loff_t off, size_t count)
> > +static int at24_read(void *priv, unsigned int off, void *val, size_t count)
> >  {
> > -	ssize_t retval = 0;
> > +	struct at24_data *at24 = priv;
> > +	char *buf = val;
> >  
> >  	if (unlikely(!count))
> >  		return count;
> > @@ -267,23 +265,21 @@ static ssize_t at24_read(struct at24_data *at24,
> >  	mutex_lock(&at24->lock);
> >  
> >  	while (count) {
> > -		ssize_t	status;
> > +		int	status;
> >  
> >  		status = at24_eeprom_read(at24, buf, off, count);

Since the patch replaces ssize_t with int here, it would also make
sense to do the same to at24_eeprom_read and at24_eeprom_write. Either
use ssize_t everywhere or nowhere.

      Andrew


From shawn.lin at rock-chips.com  Tue May  3 18:43:24 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Wed,  4 May 2016 09:43:24 +0800
Subject: [PATCH v3] mmc: sdhci-of-arasan: fix set_clock when a phy is supported
Message-ID: <1462326204-5090-1-git-send-email-shawn.lin@rock-chips.com>

commit 61b914eb81f8 ("mmc: sdhci-of-arasan: add phy support for
sdhci-of-arasan") introduce phy support for arasan. According to
the vendor's databook, we should make sure the phy is in poweroff
status before we configure the clk stuff. Otherwise it may cause
some IO sample timing issues from the test. And we don't need this
extra operation while running in low performance mode since phy
doesn't trigger sampling block.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

---

Changes in v3:
- avoid use sleep function with the scope of spinlock because
phy APIs call mutex.

Changes in v2:
- Rename commit msg title to indicate it's a fix

 drivers/mmc/host/sdhci-of-arasan.c | 26 +++++++++++++++++++++++++-
 1 file changed, 25 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 2e482b1..b6f4c1d 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -55,8 +55,32 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
 	return freq;
 }
 
+static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
+{
+	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
+	bool ctrl_phy = false;
+
+	if (clock > MMC_HIGH_52_MAX_DTR && (!IS_ERR(sdhci_arasan->phy)))
+		ctrl_phy = true;
+
+	if (ctrl_phy) {
+		spin_unlock_irq(&host->lock);
+		phy_power_off(sdhci_arasan->phy);
+		spin_lock_irq(&host->lock);
+	}
+
+	sdhci_set_clock(host, clock);
+
+	if (ctrl_phy) {
+		spin_unlock_irq(&host->lock);
+		phy_power_on(sdhci_arasan->phy);
+		spin_lock_irq(&host->lock);
+	}
+}
+
 static struct sdhci_ops sdhci_arasan_ops = {
-	.set_clock = sdhci_set_clock,
+	.set_clock = sdhci_arasan_set_clock,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
 	.get_timeout_clock = sdhci_arasan_get_timeout_clock,
 	.set_bus_width = sdhci_set_bus_width,
-- 
2.3.7




From shawn.lin at rock-chips.com  Tue May  3 18:48:55 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Wed, 4 May 2016 09:48:55 +0800
Subject: [PATCH v2] mmc: sdhci-of-arasan: fix set_clock when a phy is
 supported
In-Reply-To: <CAPDyKFp8GmNjU_G9p5u3KFPB8h-BcqL9s6FUAUnAABt8g4Bw0w@mail.gmail.com>
References: <1461832731-28422-1-git-send-email-shawn.lin@rock-chips.com>
 <CAPDyKFp8GmNjU_G9p5u3KFPB8h-BcqL9s6FUAUnAABt8g4Bw0w@mail.gmail.com>
Message-ID: <1d3a9de8-9092-add5-078e-66ce4ce5f6f3@rock-chips.com>

? 2016/4/28 18:38, Ulf Hansson ??:
> On 28 April 2016 at 10:38, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> commit 61b914eb81f8 ("mmc: sdhci-of-arasan: add phy support for
>> sdhci-of-arasan") introduce phy support for arasan. According to
>> the vendor's databook, we should make sure the phy is in poweroff
>> status before we configure the clk stuff. Otherwise it may cause
>> some IO sample timing issues from the test. And we don't need this
>> extra operation while running in low performance mode since phy
>> doesn't trigger sampling block.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>
> Thanks, applied for next!

Thanks for applying v2 but, could you please drop it and applied v3
I just send :) .
Because v2 introduces a bug. Set_clock callback will be
called under the protection of spinlock in sdhci_do_set_ios. However
PHY APIs need mutex which fails the kernel's debug check

BUG: sleeping function called from invalid context at kernel/locking/mutex.c

>
> Kind regards
> Uffe
>
>>
>> ---
>>
>> Changes in v2:
>> - change commit msg title to indicate it's a fix
>> - fix a typo in commmit msg
>>
>>  drivers/mmc/host/sdhci-of-arasan.c | 20 +++++++++++++++++++-
>>  1 file changed, 19 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
>> index 2e482b1..20b859e 100644
>> --- a/drivers/mmc/host/sdhci-of-arasan.c
>> +++ b/drivers/mmc/host/sdhci-of-arasan.c
>> @@ -55,8 +55,26 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
>>         return freq;
>>  }
>>
>> +static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
>> +{
>> +       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>> +       struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
>> +       bool ctrl_phy = false;
>> +
>> +       if (clock > MMC_HIGH_52_MAX_DTR && (!IS_ERR(sdhci_arasan->phy)))
>> +               ctrl_phy = true;
>> +
>> +       if (ctrl_phy)
>> +               phy_power_off(sdhci_arasan->phy);
>> +
>> +       sdhci_set_clock(host, clock);
>> +
>> +       if (ctrl_phy)
>> +               phy_power_on(sdhci_arasan->phy);
>> +}
>> +
>>  static struct sdhci_ops sdhci_arasan_ops = {
>> -       .set_clock = sdhci_set_clock,
>> +       .set_clock = sdhci_arasan_set_clock,
>>         .get_max_clock = sdhci_pltfm_clk_get_max_clock,
>>         .get_timeout_clock = sdhci_arasan_get_timeout_clock,
>>         .set_bus_width = sdhci_set_bus_width,
>> --
>> 2.3.7
>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
>


-- 
Best Regards
Shawn Lin



From dan.carpenter at oracle.com  Tue May  3 23:25:46 2016
From: dan.carpenter at oracle.com (Dan Carpenter)
Date: Wed, 4 May 2016 09:25:46 +0300
Subject: [patch] spi: rockchip: potential NULL dereference on error
Message-ID: <20160504062546.GG22064@mwanda>

We were calling dma_release_channel(rs->dma_tx.ch) when "rs->dma_tx.ch"
is potentially NULL.  There is actually a call to that in the unwind
code at the bottom of the function so we can just re-arrange this a bit
and remove the call.  Also there is no need to set rs->dma_tx.ch to
NULL on this error path.

Fixes: e4c0e06f949b ('spi: rockchip: fix probe deferral handling')
Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 6c6c001..cd89682 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -744,10 +744,8 @@ static int rockchip_spi_probe(struct platform_device *pdev)
 	rs->dma_rx.ch = dma_request_chan(rs->dev, "rx");
 	if (IS_ERR(rs->dma_rx.ch)) {
 		if (PTR_ERR(rs->dma_rx.ch) == -EPROBE_DEFER) {
-			dma_release_channel(rs->dma_tx.ch);
-			rs->dma_tx.ch = NULL;
 			ret = -EPROBE_DEFER;
-			goto err_get_fifo_len;
+			goto err_free_dma_tx;
 		}
 		dev_warn(rs->dev, "Failed to request RX DMA channel\n");
 		rs->dma_rx.ch = NULL;
@@ -775,10 +773,11 @@ static int rockchip_spi_probe(struct platform_device *pdev)
 
 err_register_master:
 	pm_runtime_disable(&pdev->dev);
-	if (rs->dma_tx.ch)
-		dma_release_channel(rs->dma_tx.ch);
 	if (rs->dma_rx.ch)
 		dma_release_channel(rs->dma_rx.ch);
+err_free_dma_tx:
+	if (rs->dma_tx.ch)
+		dma_release_channel(rs->dma_tx.ch);
 err_get_fifo_len:
 	clk_disable_unprepare(rs->spiclk);
 err_spiclk_enable:


From pavel at ucw.cz  Wed May  4 00:18:01 2016
From: pavel at ucw.cz (Pavel Machek)
Date: Wed, 4 May 2016 09:18:01 +0200
Subject: [PATCH v2 0/4] Patches to allow consistent mmc / mmcblk
 numbering w/ device tree
In-Reply-To: <20160429181248.GW19428@n2100.arm.linux.org.uk>
References: <1461951139-6109-1-git-send-email-dianders@chromium.org>
 <20160429181248.GW19428@n2100.arm.linux.org.uk>
Message-ID: <20160504071801.GA17045@amd>

On Fri 2016-04-29 19:12:48, Russell King - ARM Linux wrote:
> On Fri, Apr 29, 2016 at 10:32:15AM -0700, Douglas Anderson wrote:
> > This series picks patches from various different places to produce what
> > I consider the best solution to getting consistent mmc and mmcblk
> > ordering.
> > 
> > Why consistent ordering and why not just use UUIDs?  IMHO consistent
> > ordering solves a few different problems:
> 
> NAK.  Really.  Use UUIDs, that's the proper solution here.

Except that UUIDs do not solve the problem.

You have just booted of nfsroot, and you want to format u-SD card in
the external slot. How do you do that?
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


From ulf.hansson at linaro.org  Wed May  4 01:12:01 2016
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Wed, 4 May 2016 10:12:01 +0200
Subject: [PATCH v2 2/6] mmc: core: add mmc-hs400-enhanced-strobe support
In-Reply-To: <1461897995-28903-1-git-send-email-shawn.lin@rock-chips.com>
References: <1461897751-28810-1-git-send-email-shawn.lin@rock-chips.com>
 <1461897995-28903-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAPDyKFrPhBKA3g+_NMBGfw4kqonpgQzbdTSo-A5sRwqio268xw@mail.gmail.com>

On 29 April 2016 at 04:46, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> This patch introduce mmc-hs400-enhanced-strobe for platforms
> which want to enable enhanced strobe function from DT if the
> mmc host controller claims to support enhanced strobe.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>
> ---
>
> Changes in v2:
> - switch to HS400ES from Highspeed mode directly
>
>  drivers/mmc/core/host.c  | 2 ++
>  include/linux/mmc/host.h | 6 ++++++
>  2 files changed, 8 insertions(+)
>
> diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
> index e0a3ee1..eb1530a 100644
> --- a/drivers/mmc/core/host.c
> +++ b/drivers/mmc/core/host.c
> @@ -289,6 +289,8 @@ int mmc_of_parse(struct mmc_host *host)
>                 host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
>         if (of_property_read_bool(np, "mmc-hs400-1_2v"))
>                 host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
> +       if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
> +               host->caps2 |= MMC_CAP2_HS400_ENHANCED_STROBE;

How about MMC_CAP2_HS400_ES instead?

>
>         host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
>         if (host->dsr_req && (host->dsr & ~0xffff)) {
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 85800b4..11e89d3 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -302,6 +302,7 @@ struct mmc_host {
>  #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
>  #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18)    /* No physical write protect pin, assume that card is always read-write */
>  #define MMC_CAP2_NO_SDIO       (1 << 19)       /* Do not send SDIO commands during initialization */
> +#define MMC_CAP2_HS400_ENHANCED_STROBE (1 << 20) /* Host supports enhanced strobe */
>
>         mmc_pm_flag_t           pm_caps;        /* supported pm features */
>
> @@ -480,6 +481,11 @@ static inline int mmc_host_uhs(struct mmc_host *host)
>                  MMC_CAP_UHS_DDR50);
>  }
>
> +static inline int mmc_host_hs400_enhanced_strobe(struct mmc_host *host)
> +{
> +       return host->caps2 & MMC_CAP2_HS400_ENHANCED_STROBE;
> +}
> +

This helper function is to me a bit unnecessary, can you please just
check the MMC_CAP2_* when needed instead!?

>  static inline int mmc_host_packed_wr(struct mmc_host *host)
>  {
>         return host->caps2 & MMC_CAP2_PACKED_WR;

Kind regards
Uffe


From heiko at sntech.de  Wed May  4 01:35:21 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Wed, 04 May 2016 10:35:21 +0200
Subject: [PATCH v2] mmc: sdhci-of-arasan: fix set_clock when a phy is
 supported
In-Reply-To: <1d3a9de8-9092-add5-078e-66ce4ce5f6f3@rock-chips.com>
References: <1461832731-28422-1-git-send-email-shawn.lin@rock-chips.com>
 <CAPDyKFp8GmNjU_G9p5u3KFPB8h-BcqL9s6FUAUnAABt8g4Bw0w@mail.gmail.com>
 <1d3a9de8-9092-add5-078e-66ce4ce5f6f3@rock-chips.com>
Message-ID: <1879484.KeYGv3HTkz@phil>

Am Mittwoch, 4. Mai 2016, 09:48:55 schrieb Shawn Lin:
> ? 2016/4/28 18:38, Ulf Hansson ??:
> > On 28 April 2016 at 10:38, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> >> commit 61b914eb81f8 ("mmc: sdhci-of-arasan: add phy support for
> >> sdhci-of-arasan") introduce phy support for arasan. According to
> >> the vendor's databook, we should make sure the phy is in poweroff
> >> status before we configure the clk stuff. Otherwise it may cause
> >> some IO sample timing issues from the test. And we don't need this
> >> extra operation while running in low performance mode since phy
> >> doesn't trigger sampling block.
> >> 
> >> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> > 
> > Thanks, applied for next!
> 
> Thanks for applying v2 but, could you please drop it and applied v3
> I just send :) .
> Because v2 introduces a bug. Set_clock callback will be
> called under the protection of spinlock in sdhci_do_set_ios. However
> PHY APIs need mutex which fails the kernel's debug check
> 
> BUG: sleeping function called from invalid context at
> kernel/locking/mutex.c

I think in general you will need to provide a follow-up patch instead of 
replacing the old version, as Ulf might not want to restructure an already 
published branch (depends on the maintainer), especially as already other 
stuff is on top of your patch [0].


Heiko

[0] 
https://git.linaro.org/people/ulf.hansson/mmc.git/shortlog/refs/heads/next




> > Kind regards
> > Uffe
> > 
> >> ---
> >> 
> >> Changes in v2:
> >> - change commit msg title to indicate it's a fix
> >> - fix a typo in commmit msg
> >> 
> >>  drivers/mmc/host/sdhci-of-arasan.c | 20 +++++++++++++++++++-
> >>  1 file changed, 19 insertions(+), 1 deletion(-)
> >> 
> >> diff --git a/drivers/mmc/host/sdhci-of-arasan.c
> >> b/drivers/mmc/host/sdhci-of-arasan.c index 2e482b1..20b859e 100644
> >> --- a/drivers/mmc/host/sdhci-of-arasan.c
> >> +++ b/drivers/mmc/host/sdhci-of-arasan.c
> >> @@ -55,8 +55,26 @@ static unsigned int
> >> sdhci_arasan_get_timeout_clock(struct sdhci_host *host)>> 
> >>         return freq;
> >>  
> >>  }
> >> 
> >> +static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned
> >> int clock) +{
> >> +       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> >> +       struct sdhci_arasan_data *sdhci_arasan =
> >> sdhci_pltfm_priv(pltfm_host); +       bool ctrl_phy = false;
> >> +
> >> +       if (clock > MMC_HIGH_52_MAX_DTR &&
> >> (!IS_ERR(sdhci_arasan->phy)))
> >> +               ctrl_phy = true;
> >> +
> >> +       if (ctrl_phy)
> >> +               phy_power_off(sdhci_arasan->phy);
> >> +
> >> +       sdhci_set_clock(host, clock);
> >> +
> >> +       if (ctrl_phy)
> >> +               phy_power_on(sdhci_arasan->phy);
> >> +}
> >> +
> >> 
> >>  static struct sdhci_ops sdhci_arasan_ops = {
> >> 
> >> -       .set_clock = sdhci_set_clock,
> >> +       .set_clock = sdhci_arasan_set_clock,
> >> 
> >>         .get_max_clock = sdhci_pltfm_clk_get_max_clock,
> >>         .get_timeout_clock = sdhci_arasan_get_timeout_clock,
> >>         .set_bus_width = sdhci_set_bus_width,
> >> 
> >> --
> >> 2.3.7
> >> 
> >> 
> >> --
> >> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> >> the body of a message to majordomo at vger.kernel.org
> >> More majordomo info at  http://vger.kernel.org/majordomo-info.html



From shawn.lin at rock-chips.com  Wed May  4 02:19:30 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Wed, 4 May 2016 17:19:30 +0800
Subject: [PATCH v2 2/6] mmc: core: add mmc-hs400-enhanced-strobe support
In-Reply-To: <CAPDyKFrPhBKA3g+_NMBGfw4kqonpgQzbdTSo-A5sRwqio268xw@mail.gmail.com>
References: <1461897751-28810-1-git-send-email-shawn.lin@rock-chips.com>
 <1461897995-28903-1-git-send-email-shawn.lin@rock-chips.com>
 <CAPDyKFrPhBKA3g+_NMBGfw4kqonpgQzbdTSo-A5sRwqio268xw@mail.gmail.com>
Message-ID: <2c73521e-7734-7438-06ef-065722130036@rock-chips.com>

On 2016/5/4 16:12, Ulf Hansson ??:
> On 29 April 2016 at 04:46, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> This patch introduce mmc-hs400-enhanced-strobe for platforms
>> which want to enable enhanced strobe function from DT if the
>> mmc host controller claims to support enhanced strobe.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>
>> ---
>>
>> Changes in v2:
>> - switch to HS400ES from Highspeed mode directly
>>
>>  drivers/mmc/core/host.c  | 2 ++
>>  include/linux/mmc/host.h | 6 ++++++
>>  2 files changed, 8 insertions(+)
>>
>> diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
>> index e0a3ee1..eb1530a 100644
>> --- a/drivers/mmc/core/host.c
>> +++ b/drivers/mmc/core/host.c
>> @@ -289,6 +289,8 @@ int mmc_of_parse(struct mmc_host *host)
>>                 host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
>>         if (of_property_read_bool(np, "mmc-hs400-1_2v"))
>>                 host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
>> +       if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
>> +               host->caps2 |= MMC_CAP2_HS400_ENHANCED_STROBE;
>
> How about MMC_CAP2_HS400_ES instead?

MMC_CAP2_HS400_ES is fine to me.

>
>>
>>         host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
>>         if (host->dsr_req && (host->dsr & ~0xffff)) {
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index 85800b4..11e89d3 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -302,6 +302,7 @@ struct mmc_host {
>>  #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
>>  #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18)    /* No physical write protect pin, assume that card is always read-write */
>>  #define MMC_CAP2_NO_SDIO       (1 << 19)       /* Do not send SDIO commands during initialization */
>> +#define MMC_CAP2_HS400_ENHANCED_STROBE (1 << 20) /* Host supports enhanced strobe */
>>
>>         mmc_pm_flag_t           pm_caps;        /* supported pm features */
>>
>> @@ -480,6 +481,11 @@ static inline int mmc_host_uhs(struct mmc_host *host)
>>                  MMC_CAP_UHS_DDR50);
>>  }
>>
>> +static inline int mmc_host_hs400_enhanced_strobe(struct mmc_host *host)
>> +{
>> +       return host->caps2 & MMC_CAP2_HS400_ENHANCED_STROBE;
>> +}
>> +
>
> This helper function is to me a bit unnecessary, can you please just
> check the MMC_CAP2_* when needed instead!?

okay, I will deal with these two comments above.

Thanks.

>
>>  static inline int mmc_host_packed_wr(struct mmc_host *host)
>>  {
>>         return host->caps2 & MMC_CAP2_PACKED_WR;
>
> Kind regards
> Uffe
>
>
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Wed May  4 02:24:44 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Wed, 4 May 2016 17:24:44 +0800
Subject: [PATCH v2] mmc: sdhci-of-arasan: fix set_clock when a phy is
 supported
In-Reply-To: <1879484.KeYGv3HTkz@phil>
References: <1461832731-28422-1-git-send-email-shawn.lin@rock-chips.com>
 <CAPDyKFp8GmNjU_G9p5u3KFPB8h-BcqL9s6FUAUnAABt8g4Bw0w@mail.gmail.com>
 <1d3a9de8-9092-add5-078e-66ce4ce5f6f3@rock-chips.com>
 <1879484.KeYGv3HTkz@phil>
Message-ID: <f4445717-c096-7f69-5ff2-879ed8b6af67@rock-chips.com>

? 2016/5/4 16:35, Heiko Stuebner ??:
> Am Mittwoch, 4. Mai 2016, 09:48:55 schrieb Shawn Lin:
>> ? 2016/4/28 18:38, Ulf Hansson ??:
>>> On 28 April 2016 at 10:38, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>>> commit 61b914eb81f8 ("mmc: sdhci-of-arasan: add phy support for
>>>> sdhci-of-arasan") introduce phy support for arasan. According to
>>>> the vendor's databook, we should make sure the phy is in poweroff
>>>> status before we configure the clk stuff. Otherwise it may cause
>>>> some IO sample timing issues from the test. And we don't need this
>>>> extra operation while running in low performance mode since phy
>>>> doesn't trigger sampling block.
>>>>
>>>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>>
>>> Thanks, applied for next!
>>
>> Thanks for applying v2 but, could you please drop it and applied v3
>> I just send :) .
>> Because v2 introduces a bug. Set_clock callback will be
>> called under the protection of spinlock in sdhci_do_set_ios. However
>> PHY APIs need mutex which fails the kernel's debug check
>>
>> BUG: sleeping function called from invalid context at
>> kernel/locking/mutex.c
>
> I think in general you will need to provide a follow-up patch instead of
> replacing the old version, as Ulf might not want to restructure an already
> published branch (depends on the maintainer), especially as already other
> stuff is on top of your patch [0].
>

Aha.. yes I see other patches on top of mine now. Thanks for reminding
it.

Ulf, would you mind that I send a new patch to fix it, or you are prone
to restructure the next?

>
> Heiko
>
> [0]
> https://git.linaro.org/people/ulf.hansson/mmc.git/shortlog/refs/heads/next
>
>
>
>
>>> Kind regards
>>> Uffe
>>>
>>>> ---
>>>>
>>>> Changes in v2:
>>>> - change commit msg title to indicate it's a fix
>>>> - fix a typo in commmit msg
>>>>
>>>>  drivers/mmc/host/sdhci-of-arasan.c | 20 +++++++++++++++++++-
>>>>  1 file changed, 19 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/mmc/host/sdhci-of-arasan.c
>>>> b/drivers/mmc/host/sdhci-of-arasan.c index 2e482b1..20b859e 100644
>>>> --- a/drivers/mmc/host/sdhci-of-arasan.c
>>>> +++ b/drivers/mmc/host/sdhci-of-arasan.c
>>>> @@ -55,8 +55,26 @@ static unsigned int
>>>> sdhci_arasan_get_timeout_clock(struct sdhci_host *host)>>
>>>>         return freq;
>>>>
>>>>  }
>>>>
>>>> +static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned
>>>> int clock) +{
>>>> +       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
>>>> +       struct sdhci_arasan_data *sdhci_arasan =
>>>> sdhci_pltfm_priv(pltfm_host); +       bool ctrl_phy = false;
>>>> +
>>>> +       if (clock > MMC_HIGH_52_MAX_DTR &&
>>>> (!IS_ERR(sdhci_arasan->phy)))
>>>> +               ctrl_phy = true;
>>>> +
>>>> +       if (ctrl_phy)
>>>> +               phy_power_off(sdhci_arasan->phy);
>>>> +
>>>> +       sdhci_set_clock(host, clock);
>>>> +
>>>> +       if (ctrl_phy)
>>>> +               phy_power_on(sdhci_arasan->phy);
>>>> +}
>>>> +
>>>>
>>>>  static struct sdhci_ops sdhci_arasan_ops = {
>>>>
>>>> -       .set_clock = sdhci_set_clock,
>>>> +       .set_clock = sdhci_arasan_set_clock,
>>>>
>>>>         .get_max_clock = sdhci_pltfm_clk_get_max_clock,
>>>>         .get_timeout_clock = sdhci_arasan_get_timeout_clock,
>>>>         .set_bus_width = sdhci_set_bus_width,
>>>>
>>>> --
>>>> 2.3.7
>>>>
>>>>
>>>> --
>>>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>>>> the body of a message to majordomo at vger.kernel.org
>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
>
>


-- 
Best Regards
Shawn Lin



From adrian.hunter at intel.com  Wed May  4 02:54:56 2016
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Wed, 4 May 2016 12:54:56 +0300
Subject: [PATCH v3] mmc: sdhci-of-arasan: fix set_clock when a phy is
 supported
In-Reply-To: <1462326204-5090-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462326204-5090-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <5729C6F0.6000603@intel.com>

On 04/05/16 04:43, Shawn Lin wrote:
> commit 61b914eb81f8 ("mmc: sdhci-of-arasan: add phy support for
> sdhci-of-arasan") introduce phy support for arasan. According to
> the vendor's databook, we should make sure the phy is in poweroff
> status before we configure the clk stuff. Otherwise it may cause
> some IO sample timing issues from the test. And we don't need this
> extra operation while running in low performance mode since phy
> doesn't trigger sampling block.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

Acked-by: Adrian Hunter <adrian.hunter at intel.com>

> 
> ---
> 
> Changes in v3:
> - avoid use sleep function with the scope of spinlock because
> phy APIs call mutex.
> 
> Changes in v2:
> - Rename commit msg title to indicate it's a fix
> 
>  drivers/mmc/host/sdhci-of-arasan.c | 26 +++++++++++++++++++++++++-
>  1 file changed, 25 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
> index 2e482b1..b6f4c1d 100644
> --- a/drivers/mmc/host/sdhci-of-arasan.c
> +++ b/drivers/mmc/host/sdhci-of-arasan.c
> @@ -55,8 +55,32 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
>  	return freq;
>  }
>  
> +static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
> +{
> +	struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> +	struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
> +	bool ctrl_phy = false;
> +
> +	if (clock > MMC_HIGH_52_MAX_DTR && (!IS_ERR(sdhci_arasan->phy)))
> +		ctrl_phy = true;
> +
> +	if (ctrl_phy) {
> +		spin_unlock_irq(&host->lock);
> +		phy_power_off(sdhci_arasan->phy);
> +		spin_lock_irq(&host->lock);
> +	}
> +
> +	sdhci_set_clock(host, clock);
> +
> +	if (ctrl_phy) {
> +		spin_unlock_irq(&host->lock);
> +		phy_power_on(sdhci_arasan->phy);
> +		spin_lock_irq(&host->lock);
> +	}
> +}
> +
>  static struct sdhci_ops sdhci_arasan_ops = {
> -	.set_clock = sdhci_set_clock,
> +	.set_clock = sdhci_arasan_set_clock,
>  	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
>  	.get_timeout_clock = sdhci_arasan_get_timeout_clock,
>  	.set_bus_width = sdhci_set_bus_width,
> 



From ulf.hansson at linaro.org  Wed May  4 04:14:31 2016
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Wed, 4 May 2016 13:14:31 +0200
Subject: [PATCH v2] mmc: sdhci-of-arasan: fix set_clock when a phy is
 supported
In-Reply-To: <f4445717-c096-7f69-5ff2-879ed8b6af67@rock-chips.com>
References: <1461832731-28422-1-git-send-email-shawn.lin@rock-chips.com>
 <CAPDyKFp8GmNjU_G9p5u3KFPB8h-BcqL9s6FUAUnAABt8g4Bw0w@mail.gmail.com>
 <1d3a9de8-9092-add5-078e-66ce4ce5f6f3@rock-chips.com>
 <1879484.KeYGv3HTkz@phil>
 <f4445717-c096-7f69-5ff2-879ed8b6af67@rock-chips.com>
Message-ID: <CAPDyKFrhxW2TeyuTuf5zRdUZAs=8-uCoG4M6_VLdy9XAbtf8vA@mail.gmail.com>

On 4 May 2016 at 11:24, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> ? 2016/5/4 16:35, Heiko Stuebner ??:
>>
>> Am Mittwoch, 4. Mai 2016, 09:48:55 schrieb Shawn Lin:
>>>
>>> ? 2016/4/28 18:38, Ulf Hansson ??:
>>>>
>>>> On 28 April 2016 at 10:38, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>>>>
>>>>> commit 61b914eb81f8 ("mmc: sdhci-of-arasan: add phy support for
>>>>> sdhci-of-arasan") introduce phy support for arasan. According to
>>>>> the vendor's databook, we should make sure the phy is in poweroff
>>>>> status before we configure the clk stuff. Otherwise it may cause
>>>>> some IO sample timing issues from the test. And we don't need this
>>>>> extra operation while running in low performance mode since phy
>>>>> doesn't trigger sampling block.
>>>>>
>>>>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>>>
>>>>
>>>> Thanks, applied for next!
>>>
>>>
>>> Thanks for applying v2 but, could you please drop it and applied v3
>>> I just send :) .
>>> Because v2 introduces a bug. Set_clock callback will be
>>> called under the protection of spinlock in sdhci_do_set_ios. However
>>> PHY APIs need mutex which fails the kernel's debug check
>>>
>>> BUG: sleeping function called from invalid context at
>>> kernel/locking/mutex.c
>>
>>
>> I think in general you will need to provide a follow-up patch instead of
>> replacing the old version, as Ulf might not want to restructure an already
>> published branch (depends on the maintainer), especially as already other
>> stuff is on top of your patch [0].
>>
>
> Aha.. yes I see other patches on top of mine now. Thanks for reminding
> it.
>
> Ulf, would you mind that I send a new patch to fix it, or you are prone
> to restructure the next?

I re-base my next branch occasionally, as I prefer it to be as clean
as possible without obvious bisect issues.

In this case there were no conflict by just removing the patch, so I
did that, thanks!

Kind regards
Uffe


From ulf.hansson at linaro.org  Wed May  4 04:14:41 2016
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Wed, 4 May 2016 13:14:41 +0200
Subject: [PATCH v3] mmc: sdhci-of-arasan: fix set_clock when a phy is
 supported
In-Reply-To: <1462326204-5090-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462326204-5090-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAPDyKFqDZ+V62fDa_MiZTKq-PjCnUMNr6OMHEbYt5y6B+r=qVg@mail.gmail.com>

On 4 May 2016 at 03:43, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> commit 61b914eb81f8 ("mmc: sdhci-of-arasan: add phy support for
> sdhci-of-arasan") introduce phy support for arasan. According to
> the vendor's databook, we should make sure the phy is in poweroff
> status before we configure the clk stuff. Otherwise it may cause
> some IO sample timing issues from the test. And we don't need this
> extra operation while running in low performance mode since phy
> doesn't trigger sampling block.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

Thanks, applied for next!

Kind regards
Uffe

>
> ---
>
> Changes in v3:
> - avoid use sleep function with the scope of spinlock because
> phy APIs call mutex.
>
> Changes in v2:
> - Rename commit msg title to indicate it's a fix
>
>  drivers/mmc/host/sdhci-of-arasan.c | 26 +++++++++++++++++++++++++-
>  1 file changed, 25 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
> index 2e482b1..b6f4c1d 100644
> --- a/drivers/mmc/host/sdhci-of-arasan.c
> +++ b/drivers/mmc/host/sdhci-of-arasan.c
> @@ -55,8 +55,32 @@ static unsigned int sdhci_arasan_get_timeout_clock(struct sdhci_host *host)
>         return freq;
>  }
>
> +static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
> +{
> +       struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
> +       struct sdhci_arasan_data *sdhci_arasan = sdhci_pltfm_priv(pltfm_host);
> +       bool ctrl_phy = false;
> +
> +       if (clock > MMC_HIGH_52_MAX_DTR && (!IS_ERR(sdhci_arasan->phy)))
> +               ctrl_phy = true;
> +
> +       if (ctrl_phy) {
> +               spin_unlock_irq(&host->lock);
> +               phy_power_off(sdhci_arasan->phy);
> +               spin_lock_irq(&host->lock);
> +       }
> +
> +       sdhci_set_clock(host, clock);
> +
> +       if (ctrl_phy) {
> +               spin_unlock_irq(&host->lock);
> +               phy_power_on(sdhci_arasan->phy);
> +               spin_lock_irq(&host->lock);
> +       }
> +}
> +
>  static struct sdhci_ops sdhci_arasan_ops = {
> -       .set_clock = sdhci_set_clock,
> +       .set_clock = sdhci_arasan_set_clock,
>         .get_max_clock = sdhci_pltfm_clk_get_max_clock,
>         .get_timeout_clock = sdhci_arasan_get_timeout_clock,
>         .set_bus_width = sdhci_set_bus_width,
> --
> 2.3.7
>
>


From ulf.hansson at linaro.org  Wed May  4 05:02:17 2016
From: ulf.hansson at linaro.org (Ulf Hansson)
Date: Wed, 4 May 2016 14:02:17 +0200
Subject: [PATCH v2 3/6] mmc: core: implement enhanced strobe support
In-Reply-To: <1461898029-28944-1-git-send-email-shawn.lin@rock-chips.com>
References: <1461897751-28810-1-git-send-email-shawn.lin@rock-chips.com>
 <1461898029-28944-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAPDyKFogNjwNs+fKPaah_X=AfSgtXUwefzon+ZQ2a2Va5Om5Nw@mail.gmail.com>

On 29 April 2016 at 04:47, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> Controllers use data strobe line to latch data from devices
> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
> introduces enhanced strobe mode for latching cmd response from
> emmc devices to host controllers. This new feature is optional,
> so it depends both on device's cap and host's cap to decide
> whether to use it or not.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
>
> Changes in v2: None
>
>  drivers/mmc/core/bus.c   |  3 +-
>  drivers/mmc/core/mmc.c   | 77 ++++++++++++++++++++++++++++++++++++++++++++----
>  include/linux/mmc/card.h |  1 +
>  include/linux/mmc/host.h | 12 ++++++++
>  include/linux/mmc/mmc.h  |  3 ++
>  5 files changed, 89 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index 4bc48f1..7e94b9d 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>                         mmc_card_ddr52(card) ? "DDR " : "",
>                         type);
>         } else {
> -               pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> +               pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>                         mmc_hostname(card->host),
>                         mmc_card_uhs(card) ? "ultra high speed " :
>                         (mmc_card_hs(card) ? "high speed " : ""),
>                         mmc_card_hs400(card) ? "HS400 " :
>                         (mmc_card_hs200(card) ? "HS200 " : ""),
> +                       mmc_card_hs400es(card) ? "Enhanced strobe" : "",

I am not sure this informations should be printed. It's still and
HS400 card, there is no performance impact, right?

>                         mmc_card_ddr52(card) ? "DDR " : "",
>                         uhs_bus_speed_mode, type, card->rca);
>         }
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 28b477d..f45ed10 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -235,6 +235,12 @@ static void mmc_select_card_type(struct mmc_card *card)
>                 avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>         }
>
> +       if ((caps2 & MMC_CAP2_HS400_ENHANCED_STROBE) &&
> +           card->ext_csd.strobe_support &&
> +           ((card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) ||
> +            (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)))
> +               avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
> +
>         card->ext_csd.hs_max_dtr = hs_max_dtr;
>         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>         card->mmc_avail_type = avail_type;
> @@ -383,6 +389,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>                         mmc_card_set_blockaddr(card);
>         }
>
> +       card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>         card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>         mmc_select_card_type(card);
>
> @@ -1062,9 +1069,10 @@ static int mmc_select_hs400(struct mmc_card *card)
>         u8 val;
>
>         /*
> -        * HS400 mode requires 8-bit bus width
> +        * HS400(ES) mode requires 8-bit bus width
>          */
> -       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
> +       if (!(((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400) ||
> +               (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)) &&
>               host->ios.bus_width == MMC_BUS_WIDTH_8))
>                 return 0;
>
> @@ -1097,9 +1105,26 @@ static int mmc_select_hs400(struct mmc_card *card)
>         }
>
>         /* Switch card to DDR */
> +       val = EXT_CSD_DDR_BUS_WIDTH_8;
> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
> +               val |= EXT_CSD_BUS_WIDTH_STROBE;
> +               /*
> +               * Make sure we are in non-enhanced strobe mode before we
> +               * actually enable it in ext_csd.
> +               */
> +               if (host->ops->prepare_enhanced_strobe)
> +                       err = host->ops->prepare_enhanced_strobe(host, false);

1) I suggest we rename the callback to "hs400_enhanced_strobe".

2) I think this might be is a bit late to deal with restoring enhanced
strobe to off. Perhaps we should do that in mmc_set_initial_state()
instead!?

> +
> +               if (err) {
> +                       pr_err("%s: unprepare_enhanced strobe failed, err:%d\n",

Maybe pr_dbg instead?

/s/unprepare_enhanced strobe/Disable hs400 es

> +                               mmc_hostname(host), err);
> +                       return err;
> +               }
> +       }
> +
>         err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>                          EXT_CSD_BUS_WIDTH,
> -                        EXT_CSD_DDR_BUS_WIDTH_8,
> +                        val,
>                          card->ext_csd.generic_cmd6_time);
>         if (err) {
>                 pr_err("%s: switch to bus width for hs400 failed, err:%d\n",
> @@ -1124,6 +1149,35 @@ static int mmc_select_hs400(struct mmc_card *card)
>         mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>         mmc_set_bus_speed(card);
>
> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
> +               /* Controller enable enhanced strobe function */
> +               if (host->ops->prepare_enhanced_strobe)
> +                       err = host->ops->prepare_enhanced_strobe(host, true);
> +
> +               if (err) {
> +                       pr_err("%s: prepare enhanced strobe failed, err:%d\n",

Maybe pr_dbg/warn instead?

/s/prepare enhanced strobe/Enable hs400 es

> +                               mmc_hostname(host), err);
> +                       return err;
> +               }
> +
> +               /*
> +                * After switching to hs400 enhanced strobe mode, we expect to
> +                * verify whether it works or not. If controller can't handle
> +                * bus width test, compare ext_csd previously read in 1 bit mode
> +                * against ext_csd at new bus width
> +                */

Is this according to spec? If so, we should probably state that here.
If not, further explanation for *why* we do this is needed.

> +               if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
> +                       err = mmc_compare_ext_csds(card, MMC_BUS_WIDTH_8);
> +               else
> +                       err = mmc_bus_test(card, MMC_BUS_WIDTH_8);
> +
> +               if (err) {
> +                       pr_warn("%s: switch to enhanced strobe failed\n",
> +                               mmc_hostname(host));
> +                       return err;
> +               }
> +       }
> +
>         if (!send_status) {
>                 err = mmc_switch_status(card);
>                 if (err)
> @@ -1297,7 +1351,8 @@ err:
>  }
>
>  /*
> - * Activate High Speed or HS200 mode if supported.
> + * Activate High Speed or HS200 mode if supported. For HS400
> + * with enhanced strobe mode, we should activate High Speed.
>   */
>  static int mmc_select_timing(struct mmc_card *card)
>  {
> @@ -1306,7 +1361,9 @@ static int mmc_select_timing(struct mmc_card *card)
>         if (!mmc_can_ext_csd(card))
>                 goto bus_speed;
>
> -       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
> +               err = mmc_select_hs(card);
> +       else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>                 err = mmc_select_hs200(card);
>         else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>                 err = mmc_select_hs(card);
> @@ -1578,7 +1635,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>         } else if (mmc_card_hs(card)) {
>                 /* Select the desired bus width optionally */
>                 err = mmc_select_bus_width(card);
> -               if (!IS_ERR_VALUE(err)) {
> +               if (IS_ERR_VALUE(err))
> +                       goto free_card;

This is going to change the behaviour, as earlier switching the bus
width was optional. See the comment a few lines above and the
implementation of mmc_select_bus_width().

> +
> +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
> +                       /* Directly from HS to HS400-ES */
> +                       err = mmc_select_hs400(card);
> +                       if (err)
> +                               goto free_card;
> +               } else {
>                         err = mmc_select_hs_ddr(card);
>                         if (err)
>                                 goto free_card;
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index eb0151b..22defc2 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>         u8                      raw_partition_support;  /* 160 */
>         u8                      raw_rpmb_size_mult;     /* 168 */
>         u8                      raw_erased_mem_count;   /* 181 */
> +       u8                      strobe_support;         /* 184 */
>         u8                      raw_ext_csd_structure;  /* 194 */
>         u8                      raw_card_type;          /* 196 */
>         u8                      raw_driver_strength;    /* 197 */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 11e89d3..19de56c 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -19,6 +19,7 @@
>
>  #include <linux/mmc/core.h>
>  #include <linux/mmc/card.h>
> +#include <linux/mmc/mmc.h>
>  #include <linux/mmc/pm.h>
>
>  struct mmc_ios {
> @@ -143,6 +144,8 @@ struct mmc_host_ops {
>
>         /* Prepare HS400 target operating frequency depending host driver */
>         int     (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
> +       /* Prepare enhanced strobe depending host driver */
> +       int     (*prepare_enhanced_strobe)(struct mmc_host *host, bool enable);
>         int     (*select_drive_strength)(struct mmc_card *card,
>                                          unsigned int max_dtr, int host_drv,
>                                          int card_drv, int *drv_type);
> @@ -518,6 +521,15 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>         return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>  }
>
> +static inline bool mmc_card_hs400es(struct mmc_card *card)
> +{
> +       if (mmc_card_hs400(card) &&
> +           (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES))
> +               return 1;
> +
> +       return 0;
> +}
> +
>  void mmc_retune_timer_stop(struct mmc_host *host);
>
>  static inline void mmc_retune_needed(struct mmc_host *host)
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 15f2c4a..c376209 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -297,6 +297,7 @@ struct _mmc_csd {
>  #define EXT_CSD_PART_CONFIG            179     /* R/W */
>  #define EXT_CSD_ERASED_MEM_CONT                181     /* RO */
>  #define EXT_CSD_BUS_WIDTH              183     /* R/W */
> +#define EXT_CSD_STROBE_SUPPORT         184     /* RO */
>  #define EXT_CSD_HS_TIMING              185     /* R/W */
>  #define EXT_CSD_POWER_CLASS            187     /* R/W */
>  #define EXT_CSD_REV                    192     /* RO */
> @@ -380,12 +381,14 @@ struct _mmc_csd {
>  #define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<7)  /* Card can run at 200MHz DDR, 1.2V */
>  #define EXT_CSD_CARD_TYPE_HS400                (EXT_CSD_CARD_TYPE_HS400_1_8V | \
>                                          EXT_CSD_CARD_TYPE_HS400_1_2V)
> +#define EXT_CSD_CARD_TYPE_HS400ES      (1<<8)  /* Card can run at HS400ES */
>
>  #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
>  #define EXT_CSD_BUS_WIDTH_8    2       /* Card is in 8 bit mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_4        5       /* Card is in 4 bit DDR mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_8        6       /* Card is in 8 bit DDR mode */
> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)        /* Enhanced strobe mode */
>
>  #define EXT_CSD_TIMING_BC      0       /* Backwards compatility */
>  #define EXT_CSD_TIMING_HS      1       /* High speed */
> --
> 2.3.7
>
>

Kind regards
Uffe


From robh+dt at kernel.org  Wed May  4 05:25:42 2016
From: robh+dt at kernel.org (Rob Herring)
Date: Wed, 4 May 2016 07:25:42 -0500
Subject: [PATCH v2 0/4] Patches to allow consistent mmc / mmcblk numbering
 w/ device tree
In-Reply-To: <20160504071801.GA17045@amd>
References: <1461951139-6109-1-git-send-email-dianders@chromium.org>
 <20160429181248.GW19428@n2100.arm.linux.org.uk> <20160504071801.GA17045@amd>
Message-ID: <CAL_JsqJ4Pzuip9VUpwryy_xK6XSZ6E+kus3wD=T4wcTHav=9iA@mail.gmail.com>

On Wed, May 4, 2016 at 2:18 AM, Pavel Machek <pavel at ucw.cz> wrote:
> On Fri 2016-04-29 19:12:48, Russell King - ARM Linux wrote:
>> On Fri, Apr 29, 2016 at 10:32:15AM -0700, Douglas Anderson wrote:
>> > This series picks patches from various different places to produce what
>> > I consider the best solution to getting consistent mmc and mmcblk
>> > ordering.
>> >
>> > Why consistent ordering and why not just use UUIDs?  IMHO consistent
>> > ordering solves a few different problems:
>>
>> NAK.  Really.  Use UUIDs, that's the proper solution here.
>
> Except that UUIDs do not solve the problem.
>
> You have just booted of nfsroot, and you want to format u-SD card in
> the external slot. How do you do that?

The same way you format a USB stick when you insert it.

If you have built-in versus removable, then we should expose that
information to userspace rather than some arbitrary encoding in DT
that 0 means built-in and 1 means removable. Or if you have multiple
slots, then use "label" to provide meaningful slot names.

Rob


From pavel at ucw.cz  Wed May  4 05:46:53 2016
From: pavel at ucw.cz (Pavel Machek)
Date: Wed, 4 May 2016 14:46:53 +0200
Subject: [PATCH v2 0/4] Patches to allow consistent mmc / mmcblk
 numbering w/ device tree
In-Reply-To: <CAL_JsqJ4Pzuip9VUpwryy_xK6XSZ6E+kus3wD=T4wcTHav=9iA@mail.gmail.com>
References: <1461951139-6109-1-git-send-email-dianders@chromium.org>
 <20160429181248.GW19428@n2100.arm.linux.org.uk>
 <20160504071801.GA17045@amd>
 <CAL_JsqJ4Pzuip9VUpwryy_xK6XSZ6E+kus3wD=T4wcTHav=9iA@mail.gmail.com>
Message-ID: <20160504124653.GA23838@amd>

On Wed 2016-05-04 07:25:42, Rob Herring wrote:
> On Wed, May 4, 2016 at 2:18 AM, Pavel Machek <pavel at ucw.cz> wrote:
> > On Fri 2016-04-29 19:12:48, Russell King - ARM Linux wrote:
> >> On Fri, Apr 29, 2016 at 10:32:15AM -0700, Douglas Anderson wrote:
> >> > This series picks patches from various different places to produce what
> >> > I consider the best solution to getting consistent mmc and mmcblk
> >> > ordering.
> >> >
> >> > Why consistent ordering and why not just use UUIDs?  IMHO consistent
> >> > ordering solves a few different problems:
> >>
> >> NAK.  Really.  Use UUIDs, that's the proper solution here.
> >
> > Except that UUIDs do not solve the problem.
> >
> > You have just booted of nfsroot, and you want to format u-SD card in
> > the external slot. How do you do that?
> 
> The same way you format a USB stick when you insert it.

Well, and that actually brings related question "how do you format the
right USB stick if you have 5 of them connected". PCs don't have good
solution, but that does not mean it can't be solved.

And no, its not really the same. At least in N900 case, I'm not really
sure if you are expected to manipulate the u-SD card while the system
is on. It is under battery cover.

> If you have built-in versus removable, then we should expose that
> information to userspace rather than some arbitrary encoding in DT
> that 0 means built-in and 1 means removable. Or if you have multiple
> slots, then use "label" to provide meaningful slot names.

Yes, labels would be nice. Plus the slot numbers should be stable, so
that booting does not randomly break.
									Pavel
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html


From adrian.hunter at intel.com  Wed May  4 05:07:01 2016
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Wed, 4 May 2016 15:07:01 +0300
Subject: [PATCH v2 3/6] mmc: core: implement enhanced strobe support
In-Reply-To: <CAPDyKFogNjwNs+fKPaah_X=AfSgtXUwefzon+ZQ2a2Va5Om5Nw@mail.gmail.com>
References: <1461897751-28810-1-git-send-email-shawn.lin@rock-chips.com>
 <1461898029-28944-1-git-send-email-shawn.lin@rock-chips.com>
 <CAPDyKFogNjwNs+fKPaah_X=AfSgtXUwefzon+ZQ2a2Va5Om5Nw@mail.gmail.com>
Message-ID: <5729E5E5.6000409@intel.com>

>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> index 4bc48f1..7e94b9d 100644
>> --- a/drivers/mmc/core/bus.c
>> +++ b/drivers/mmc/core/bus.c
>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>                         mmc_card_ddr52(card) ? "DDR " : "",
>>                         type);
>>         } else {
>> -               pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>> +               pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>                         mmc_hostname(card->host),
>>                         mmc_card_uhs(card) ? "ultra high speed " :
>>                         (mmc_card_hs(card) ? "high speed " : ""),
>>                         mmc_card_hs400(card) ? "HS400 " :
>>                         (mmc_card_hs200(card) ? "HS200 " : ""),
>> +                       mmc_card_hs400es(card) ? "Enhanced strobe" : "",
> 
> I am not sure this informations should be printed. It's still and
> HS400 card, there is no performance impact, right?

I actually asked for that I think.  HS400ES does not need re-tuning so there
is a performance and behavioural change which I think it is very useful to
know.  Kernels which don't support HS400ES will show "HS400" whereas kernels
which do support it will show something different.



From broonie at kernel.org  Wed May  4 06:56:56 2016
From: broonie at kernel.org (Mark Brown)
Date: Wed, 04 May 2016 14:56:56 +0100
Subject: Applied "spi: rockchip: potential NULL dereference on error" to the
 spi tree
In-Reply-To: <20160504062546.GG22064@mwanda>
Message-ID: <E1axxIO-0001hK-3n@debutante>

The patch

   spi: rockchip: potential NULL dereference on error

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 5de7ed0c980c4bcfd8ea5c0b84a61b76df7d6c08 Mon Sep 17 00:00:00 2001
From: Dan Carpenter <dan.carpenter at oracle.com>
Date: Wed, 4 May 2016 09:25:46 +0300
Subject: [PATCH] spi: rockchip: potential NULL dereference on error

We were calling dma_release_channel(rs->dma_tx.ch) when "rs->dma_tx.ch"
is potentially NULL.  There is actually a call to that in the unwind
code at the bottom of the function so we can just re-arrange this a bit
and remove the call.  Also there is no need to set rs->dma_tx.ch to
NULL on this error path.

Fixes: e4c0e06f949b ('spi: rockchip: fix probe deferral handling')
Signed-off-by: Dan Carpenter <dan.carpenter at oracle.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 drivers/spi/spi-rockchip.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 6c6c0013ec7a..cd89682065b9 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -744,10 +744,8 @@ static int rockchip_spi_probe(struct platform_device *pdev)
 	rs->dma_rx.ch = dma_request_chan(rs->dev, "rx");
 	if (IS_ERR(rs->dma_rx.ch)) {
 		if (PTR_ERR(rs->dma_rx.ch) == -EPROBE_DEFER) {
-			dma_release_channel(rs->dma_tx.ch);
-			rs->dma_tx.ch = NULL;
 			ret = -EPROBE_DEFER;
-			goto err_get_fifo_len;
+			goto err_free_dma_tx;
 		}
 		dev_warn(rs->dev, "Failed to request RX DMA channel\n");
 		rs->dma_rx.ch = NULL;
@@ -775,10 +773,11 @@ static int rockchip_spi_probe(struct platform_device *pdev)
 
 err_register_master:
 	pm_runtime_disable(&pdev->dev);
-	if (rs->dma_tx.ch)
-		dma_release_channel(rs->dma_tx.ch);
 	if (rs->dma_rx.ch)
 		dma_release_channel(rs->dma_rx.ch);
+err_free_dma_tx:
+	if (rs->dma_tx.ch)
+		dma_release_channel(rs->dma_tx.ch);
 err_get_fifo_len:
 	clk_disable_unprepare(rs->spiclk);
 err_spiclk_enable:
-- 
2.8.1



From david.wu at rock-chips.com  Wed May  4 07:13:05 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed,  4 May 2016 22:13:05 +0800
Subject: [PATCH v7 0/9] add i2c driver supported for rk3399
Message-ID: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>

There are two points differert from others:
 - new method to caculate i2c timings for rk3399
 - pclk and function clk are separated at rk3399

David Wu (9):
  i2c: rk3x: add documentation to fields in "struct rk3x_i2c"
  i2c: rk3x: use struct "rk3x_i2c_calced_timings"
  i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
  i2c: rk3x: Move setting STATE_START and add STATE_SETUP
  i2c: rk3x: Change SoC data to not use array
  i2c: rk3x: Move spec timing data to "static const" structs
  dt-bindings: i2c: rk3x: add support for rk3399
  i2c: rk3x: add i2c support for rk3399 soc
  i2c: rk3x: support fast-mode plus for rk3399

 Documentation/devicetree/bindings/i2c/i2c-rk3x.txt |  16 +-
 drivers/i2c/busses/i2c-rk3x.c                      | 482 +++++++++++++++++----
 2 files changed, 419 insertions(+), 79 deletions(-)

-- 
1.9.1




From david.wu at rock-chips.com  Wed May  4 07:13:06 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed,  4 May 2016 22:13:06 +0800
Subject: [PATCH v7 1/9] i2c: rk3x: add documentation to fields in "struct
 rk3x_i2c"
In-Reply-To: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462371194-5809-2-git-send-email-david.wu@rock-chips.com>

Signed-off-by: David Wu <david.wu at rock-chips.com>
---
Change in v7:
- none

 drivers/i2c/busses/i2c-rk3x.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 80bed02..7e45d51 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -90,6 +90,26 @@ struct rk3x_i2c_soc_data {
 	int grf_offset;
 };
 
+/**
+ * struct rk3x_i2c - private data of the controller
+ * @adap: corresponding I2C adapter
+ * @dev: device for this controller
+ * @soc_data: related soc data struct
+ * @regs: virtual memory area
+ * @clk: clock of i2c bus
+ * @clk_rate_nb: i2c clk rate change notify
+ * @t: I2C known timing information
+ * @lock: spinlock for the i2c bus
+ * @wait: the waitqueue to wait for i2c transfer
+ * @busy: the condition for the event to wait for
+ * @msg: current i2c message
+ * @addr: addr of i2c slave device
+ * @mode: mode of i2c transfer
+ * @is_last_msg: flag determines whether it is the last msg in this transfer
+ * @state: state of i2c transfer
+ * @processed: byte length which has been send or received
+ * @error: error code for i2c transfer
+ */
 struct rk3x_i2c {
 	struct i2c_adapter adap;
 	struct device *dev;
@@ -116,7 +136,7 @@ struct rk3x_i2c {
 
 	/* I2C state machine */
 	enum rk3x_i2c_state state;
-	unsigned int processed; /* sent/received bytes */
+	unsigned int processed;
 	int error;
 };
 
-- 
1.9.1




From david.wu at rock-chips.com  Wed May  4 07:13:07 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed,  4 May 2016 22:13:07 +0800
Subject: [PATCH v7 2/9] i2c: rk3x: use struct "rk3x_i2c_calced_timings"
In-Reply-To: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462371194-5809-3-git-send-email-david.wu@rock-chips.com>

Signed-off-by: David Wu <david.wu at rock-chips.com>
---
Change in v7:
- none

 drivers/i2c/busses/i2c-rk3x.c | 55 +++++++++++++++++++++++++------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 7e45d51..1e2677a 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -75,6 +75,16 @@ enum {
 #define WAIT_TIMEOUT      1000 /* ms */
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
+/**
+ * struct rk3x_i2c_calced_timings:
+ * @div_low: Divider output for low
+ * @div_high: Divider output for high
+ */
+struct rk3x_i2c_calced_timings {
+	unsigned long div_low;
+	unsigned long div_high;
+};
+
 enum rk3x_i2c_state {
 	STATE_IDLE,
 	STATE_START,
@@ -454,9 +464,8 @@ out:
  * Calculate divider values for desired SCL frequency
  *
  * @clk_rate: I2C input clock rate
- * @t: Known I2C timing information.
- * @div_low: Divider output for low
- * @div_high: Divider output for high
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
  *
  * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
@@ -464,8 +473,7 @@ out:
  */
 static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 			      struct i2c_timings *t,
-			      unsigned long *div_low,
-			      unsigned long *div_high)
+			      struct rk3x_i2c_calced_timings *t_calc)
 {
 	unsigned long spec_min_low_ns, spec_min_high_ns;
 	unsigned long spec_setup_start, spec_max_data_hold_ns;
@@ -572,8 +580,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 		 * Time needed to meet hold requirements is important.
 		 * Just use that.
 		 */
-		*div_low = min_low_div;
-		*div_high = min_high_div;
+		t_calc->div_low = min_low_div;
+		t_calc->div_high = min_high_div;
 	} else {
 		/*
 		 * We've got to distribute some time among the low and high
@@ -602,25 +610,25 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 
 		/* Give low the "ideal" and give high whatever extra is left */
 		extra_low_div = ideal_low_div - min_low_div;
-		*div_low = ideal_low_div;
-		*div_high = min_high_div + (extra_div - extra_low_div);
+		t_calc->div_low = ideal_low_div;
+		t_calc->div_high = min_high_div + (extra_div - extra_low_div);
 	}
 
 	/*
 	 * Adjust to the fact that the hardware has an implicit "+1".
 	 * NOTE: Above calculations always produce div_low > 0 and div_high > 0.
 	 */
-	*div_low = *div_low - 1;
-	*div_high = *div_high - 1;
+	t_calc->div_low--;
+	t_calc->div_high--;
 
 	/* Maximum divider supported by hw is 0xffff */
-	if (*div_low > 0xffff) {
-		*div_low = 0xffff;
+	if (t_calc->div_low > 0xffff) {
+		t_calc->div_low = 0xffff;
 		ret = -EINVAL;
 	}
 
-	if (*div_high > 0xffff) {
-		*div_high = 0xffff;
+	if (t_calc->div_high > 0xffff) {
+		t_calc->div_high = 0xffff;
 		ret = -EINVAL;
 	}
 
@@ -630,19 +638,21 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 {
 	struct i2c_timings *t = &i2c->t;
-	unsigned long div_low, div_high;
+	struct rk3x_i2c_calced_timings calc;
 	u64 t_low_ns, t_high_ns;
 	int ret;
 
-	ret = rk3x_i2c_calc_divs(clk_rate, t, &div_low, &div_high);
+	ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
 	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
 
 	clk_enable(i2c->clk);
-	i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV);
+	i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
+		   REG_CLKDIV);
 	clk_disable(i2c->clk);
 
-	t_low_ns = div_u64(((u64)div_low + 1) * 8 * 1000000000, clk_rate);
-	t_high_ns = div_u64(((u64)div_high + 1) * 8 * 1000000000, clk_rate);
+	t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
+	t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
+			    clk_rate);
 	dev_dbg(i2c->dev,
 		"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
 		clk_rate / 1000,
@@ -672,12 +682,11 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
 {
 	struct clk_notifier_data *ndata = data;
 	struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
-	unsigned long div_low, div_high;
+	struct rk3x_i2c_calced_timings calc;
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
-		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t,
-				       &div_low, &div_high) != 0)
+		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0)
 			return NOTIFY_STOP;
 
 		/* scale up */
-- 
1.9.1




From david.wu at rock-chips.com  Wed May  4 07:13:09 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed,  4 May 2016 22:13:09 +0800
Subject: [PATCH v7 4/9] i2c: rk3x: Move setting STATE_START and add STATE_SETUP
In-Reply-To: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462371194-5809-5-git-send-email-david.wu@rock-chips.com>

Signed-off-by: David Wu <david.wu at rock-chips.com>
---
Change in v7:
- none

 drivers/i2c/busses/i2c-rk3x.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 9eeb4e5..0838fcf 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -87,6 +87,7 @@ struct rk3x_i2c_calced_timings {
 
 enum rk3x_i2c_state {
 	STATE_IDLE,
+	STATE_SETUP,
 	STATE_START,
 	STATE_READ,
 	STATE_WRITE,
@@ -174,6 +175,7 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
 	u32 val;
 
+	i2c->state = STATE_START;
 	i2c_writel(i2c, REG_INT_START, REG_IEN);
 
 	/* enable adapter with correct mode, send START condition */
@@ -451,6 +453,7 @@ static irqreturn_t rk3x_i2c_irq(int irqno, void *dev_id)
 		rk3x_i2c_handle_stop(i2c, ipd);
 		break;
 	case STATE_IDLE:
+	case STATE_SETUP:
 		break;
 	}
 
@@ -781,7 +784,7 @@ static int rk3x_i2c_setup(struct rk3x_i2c *i2c, struct i2c_msg *msgs, int num)
 
 	i2c->addr = msgs[0].addr;
 	i2c->busy = true;
-	i2c->state = STATE_START;
+	i2c->state = STATE_SETUP;
 	i2c->processed = 0;
 	i2c->error = 0;
 
-- 
1.9.1




From david.wu at rock-chips.com  Wed May  4 07:13:08 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed,  4 May 2016 22:13:08 +0800
Subject: [PATCH v7 3/9] i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
In-Reply-To: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462371194-5809-4-git-send-email-david.wu@rock-chips.com>

Call rk3x_i2c_setup() before rk3x_i2c_start()
and the last thing in setup was to clean the IPD,
so no reason to do it at the beginning of start.

Signed-off-by: David Wu <david.wu at rock-chips.com>
---
Change in v7:
- none

 drivers/i2c/busses/i2c-rk3x.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 1e2677a..9eeb4e5 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -174,7 +174,6 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
 	u32 val;
 
-	rk3x_i2c_clean_ipd(i2c);
 	i2c_writel(i2c, REG_INT_START, REG_IEN);
 
 	/* enable adapter with correct mode, send START condition */
-- 
1.9.1




From david.wu at rock-chips.com  Wed May  4 07:33:38 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed,  4 May 2016 22:33:38 +0800
Subject: [PATCH v7 5/9] i2c: rk3x: Change SoC data to not use array
In-Reply-To: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462372418-6349-1-git-send-email-david.wu@rock-chips.com>

Signed-off-by: David Wu <david.wu at rock-chips.com>
---
 drivers/i2c/busses/i2c-rk3x.c | 38 ++++++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 0838fcf..9686c81 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -867,17 +867,39 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
 	.functionality		= rk3x_i2c_func,
 };
 
-static struct rk3x_i2c_soc_data soc_data[3] = {
-	{ .grf_offset = 0x154 }, /* rk3066 */
-	{ .grf_offset = 0x0a4 }, /* rk3188 */
-	{ .grf_offset = -1 },    /* no I2C switching needed */
+static const struct rk3x_i2c_soc_data rk3066_soc_data = {
+	.grf_offset = 0x154,
+};
+
+static const struct rk3x_i2c_soc_data rk3188_soc_data = {
+	.grf_offset = 0x0a4,
+};
+
+static const struct rk3x_i2c_soc_data rk3228_soc_data = {
+	.grf_offset = -1,
+};
+
+static const struct rk3x_i2c_soc_data rk3288_soc_data = {
+	.grf_offset = -1,
 };
 
 static const struct of_device_id rk3x_i2c_match[] = {
-	{ .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] },
-	{ .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] },
-	{ .compatible = "rockchip,rk3228-i2c", .data = (void *)&soc_data[2] },
-	{ .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] },
+	{
+		.compatible = "rockchip,rk3066-i2c",
+		.data = (void *)&rk3066_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3188-i2c",
+		.data = (void *)&rk3188_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3228-i2c",
+		.data = (void *)&rk3228_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3288-i2c",
+		.data = (void *)&rk3288_soc_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
-- 
1.9.1




From david.wu at rock-chips.com  Wed May  4 07:34:32 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed,  4 May 2016 22:34:32 +0800
Subject: [PATCH v7 6/9] i2c: rk3x: Move spec timing data to "static const"
 structs
In-Reply-To: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462372472-6396-1-git-send-email-david.wu@rock-chips.com>

Signed-off-by: David Wu <david.wu at rock-chips.com>
---
 drivers/i2c/busses/i2c-rk3x.c | 100 ++++++++++++++++++++++++++++++------------
 1 file changed, 72 insertions(+), 28 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 9686c81..408f9ab 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -76,6 +76,51 @@ enum {
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
 /**
+ * struct i2c_spec_values:
+ * @min_hold_start_ns: min hold time (repeated) START condition
+ * @min_low_ns: min LOW period of the SCL clock
+ * @min_high_ns: min HIGH period of the SCL cloc
+ * @min_setup_start_ns: min set-up time for a repeated START conditio
+ * @max_data_hold_ns: max data hold time
+ * @min_data_setup_ns: min data set-up time
+ * @min_setup_stop_ns: min set-up time for STOP condition
+ * @min_hold_buffer_ns: min bus free time between a STOP and
+ * START condition
+ */
+struct i2c_spec_values {
+	unsigned long min_hold_start_ns;
+	unsigned long min_low_ns;
+	unsigned long min_high_ns;
+	unsigned long min_setup_start_ns;
+	unsigned long max_data_hold_ns;
+	unsigned long min_data_setup_ns;
+	unsigned long min_setup_stop_ns;
+	unsigned long min_hold_buffer_ns;
+};
+
+static const struct i2c_spec_values standard_mode_spec = {
+	.min_hold_start_ns = 4000,
+	.min_low_ns = 4700,
+	.min_high_ns = 4000,
+	.min_setup_start_ns = 4700,
+	.max_data_hold_ns = 3450,
+	.min_data_setup_ns = 250,
+	.min_setup_stop_ns = 4000,
+	.min_hold_buffer_ns = 4700,
+};
+
+static const struct i2c_spec_values fast_mode_spec = {
+	.min_hold_start_ns = 600,
+	.min_low_ns = 1300,
+	.min_high_ns = 600,
+	.min_setup_start_ns = 600,
+	.max_data_hold_ns = 900,
+	.min_data_setup_ns = 100,
+	.min_setup_stop_ns = 600,
+	.min_hold_buffer_ns = 1300,
+};
+
+/**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
  * @div_high: Divider output for high
@@ -463,6 +508,21 @@ out:
 }
 
 /**
+ * Get timing values of I2C specification
+ *
+ * @speed: Desired SCL frequency
+ *
+ * Returns: Matched i2c spec values.
+ */
+static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
+{
+	if (speed <= 100000)
+		return &standard_mode_spec;
+	else
+		return &fast_mode_spec;
+}
+
+/**
  * Calculate divider values for desired SCL frequency
  *
  * @clk_rate: I2C input clock rate
@@ -477,10 +537,6 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 			      struct i2c_timings *t,
 			      struct rk3x_i2c_calced_timings *t_calc)
 {
-	unsigned long spec_min_low_ns, spec_min_high_ns;
-	unsigned long spec_setup_start, spec_max_data_hold_ns;
-	unsigned long data_hold_buffer_ns;
-
 	unsigned long min_low_ns, min_high_ns;
 	unsigned long max_low_ns, min_total_ns;
 
@@ -492,6 +548,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	unsigned long min_div_for_hold, min_total_div;
 	unsigned long extra_div, extra_low_div, ideal_low_div;
 
+	unsigned long data_hold_buffer_ns = 50;
+	const struct i2c_spec_values *spec;
 	int ret = 0;
 
 	/* Only support standard-mode and fast-mode */
@@ -514,22 +572,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	 *	 This is because the i2c host on Rockchip holds the data line
 	 *	 for half the low time.
 	 */
-	if (t->bus_freq_hz <= 100000) {
-		/* Standard-mode */
-		spec_min_low_ns = 4700;
-		spec_setup_start = 4700;
-		spec_min_high_ns = 4000;
-		spec_max_data_hold_ns = 3450;
-		data_hold_buffer_ns = 50;
-	} else {
-		/* Fast-mode */
-		spec_min_low_ns = 1300;
-		spec_setup_start = 600;
-		spec_min_high_ns = 600;
-		spec_max_data_hold_ns = 900;
-		data_hold_buffer_ns = 50;
-	}
-	min_high_ns = t->scl_rise_ns + spec_min_high_ns;
+	spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+	min_high_ns = t->scl_rise_ns + spec->min_high_ns;
 
 	/*
 	 * Timings for repeated start:
@@ -539,14 +583,14 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	 * We need to account for those rules in picking our "high" time so
 	 * we meet tSU;STA and tHD;STA times.
 	 */
-	min_high_ns = max(min_high_ns,
-		DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875));
-	min_high_ns = max(min_high_ns,
-		DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start +
-			      t->sda_fall_ns + spec_min_high_ns), 2));
-
-	min_low_ns = t->scl_fall_ns + spec_min_low_ns;
-	max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
+	min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+		(t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875));
+	min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+		(t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns +
+		spec->min_high_ns), 2));
+
+	min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+	max_low_ns =  spec->max_data_hold_ns * 2 - data_hold_buffer_ns;
 	min_total_ns = min_low_ns + min_high_ns;
 
 	/* Adjust to avoid overflow */
-- 
1.9.1




From david.wu at rock-chips.com  Wed May  4 07:35:23 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed,  4 May 2016 22:35:23 +0800
Subject: [PATCH v7 7/9] dt-bindings: i2c: rk3x: add support for rk3399
In-Reply-To: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462372523-6444-1-git-send-email-david.wu@rock-chips.com>

The bus clock and function clock are separated at rk3399,
and others use one clock as the bus clock and function clock.

Signed-off-by: David Wu <david.wu at rock-chips.com>
---
 Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
index 0b4a85f..82b6f6b 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
@@ -6,10 +6,20 @@ RK3xxx SoCs.
 Required properties :
 
  - reg : Offset and length of the register set for the device
- - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c",
-		"rockchip,rk3228-i2c" or "rockchip,rk3288-i2c".
+ - compatible: should be one of the followings
+   - "rockchip,rk3066-i2c": for rk3066
+   - "rockchip,rk3188-i2c": for rk3188
+   - "rockchip,rk3228-i2c": for rk3228
+   - "rockchip,rk3288-i2c": for rk3288
+   - "rockchip,rk3399-i2c": for rk3399
  - interrupts : interrupt number
- - clocks : parent clock
+ - clocks: See ../clock/clock-bindings.txt
+   - For older hardware (rk3066, rk3188, rk3228, rk3288):
+     - There is one clock that's used both to derive the functional clock
+       for the device and as the bus clock.  REQUIRED.
+   - For newer hardware (rk3399): specify by name
+     - "i2c": REQUIRED. This is used to derive the functional clock.
+     - "pclk": REQUIRED. This is the bus clock.equired on RK3066, RK3188 :
 
 Required on RK3066, RK3188 :
 
-- 
1.9.1




From david.wu at rock-chips.com  Wed May  4 07:36:49 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed,  4 May 2016 22:36:49 +0800
Subject: [PATCH v7 8/9] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462372609-6535-1-git-send-email-david.wu@rock-chips.com>

- new method to caculate i2c timings for rk3399:
  There was an timing issue about "repeated start" time at the I2C
  controller of version0, controller appears to drop SDA at .875x (7/8)
  programmed clk high. On version 1 of the controller, the rule(.875x)
  isn't enough to meet tSU;STA
  requirements on 100k's Standard-mode. To resolve this issue,
  sda_update_config, start_setup_config and stop_setup_config for I2C
  timing information are added, new rules are designed to calculate
  the timing information at new v1.
- pclk and function clk are separated at rk3399

Signed-off-by: David Wu <david.wu at rock-chips.com>
---
Changes in v7:
- transform into a 9 series patches (Doug)
- drop highspeed with mastercode, and support fast-mode plus (Doug)

Changes in v6:
- add master code send for HS mode
- use assigned-clocks mechanism for clock rate set form DT (Heiko)

Changes in v5:
- use compatible to seperate from different version
- can caculate highspeed clk rate

Changes in v4:
- pclk and sclk are treated individually
- use switch-case to seperate from different version (Andy)
- fix dead loop form Julia's notice

Change in v3:
- Too many arguments for ops func, use struct for them (Andy)

 drivers/i2c/busses/i2c-rk3x.c | 266 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 243 insertions(+), 23 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 408f9ab..47368c4 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -58,6 +58,10 @@ enum {
 #define REG_CON_LASTACK   BIT(5) /* 1: send NACK after last received byte */
 #define REG_CON_ACTACK    BIT(6) /* 1: stop if NACK is received */
 
+#define REG_CON_SDA_CFG(cfg) ((cfg) << 8)
+#define REG_CON_STA_CFG(cfg) ((cfg) << 12)
+#define REG_CON_STO_CFG(cfg) ((cfg) << 14)
+
 /* REG_MRXADDR bits */
 #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
 
@@ -124,10 +128,15 @@ static const struct i2c_spec_values fast_mode_spec = {
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
  * @div_high: Divider output for high
+ * @tuning: Used to adjust setup/hold data time,
+ * setup/hold start time and setup stop time for
+ * v1's calc_timings, the tuning should all be 0
+ * for old hardware anyone using v0's calc_timings.
  */
 struct rk3x_i2c_calced_timings {
 	unsigned long div_low;
 	unsigned long div_high;
+	unsigned int tuning;
 };
 
 enum rk3x_i2c_state {
@@ -141,9 +150,12 @@ enum rk3x_i2c_state {
 
 /**
  * @grf_offset: offset inside the grf regmap for setting the i2c type
+ * @calc_timings: Callback function for i2c timing information calculated
  */
 struct rk3x_i2c_soc_data {
 	int grf_offset;
+	int (*calc_timings)(unsigned long, struct i2c_timings *,
+			    struct rk3x_i2c_calced_timings *);
 };
 
 /**
@@ -152,9 +164,11 @@ struct rk3x_i2c_soc_data {
  * @dev: device for this controller
  * @soc_data: related soc data struct
  * @regs: virtual memory area
- * @clk: clock of i2c bus
+ * @clk: function clk for rk3399 or function & Bus clks for others
+ * @pclk: Bus clk for rk3399
  * @clk_rate_nb: i2c clk rate change notify
  * @t: I2C known timing information
+ * @t_calc: I2C timing information need to be calculated
  * @lock: spinlock for the i2c bus
  * @wait: the waitqueue to wait for i2c transfer
  * @busy: the condition for the event to wait for
@@ -174,10 +188,12 @@ struct rk3x_i2c {
 	/* Hardware resources */
 	void __iomem *regs;
 	struct clk *clk;
+	struct clk *pclk;
 	struct notifier_block clk_rate_nb;
 
 	/* Settings */
 	struct i2c_timings t;
+	struct rk3x_i2c_calced_timings t_calc;
 
 	/* Synchronization & notification */
 	spinlock_t lock;
@@ -218,13 +234,13 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
  */
 static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
-	u32 val;
+	u32 val = i2c->t_calc.tuning;
 
 	i2c->state = STATE_START;
 	i2c_writel(i2c, REG_INT_START, REG_IEN);
 
 	/* enable adapter with correct mode, send START condition */
-	val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
+	val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
 
 	/* if we want to react to NACK, set ACTACK bit */
 	if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
@@ -533,9 +549,9 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
  * a best-effort divider value is returned in divs. If the target rate is
  * too high, we silently use the highest possible rate.
  */
-static int rk3x_i2c_calc_divs(unsigned long clk_rate,
-			      struct i2c_timings *t,
-			      struct rk3x_i2c_calced_timings *t_calc)
+static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
+				    struct i2c_timings *t,
+				    struct rk3x_i2c_calced_timings *t_calc)
 {
 	unsigned long min_low_ns, min_high_ns;
 	unsigned long max_low_ns, min_total_ns;
@@ -681,23 +697,189 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	return ret;
 }
 
+/**
+ * Calculate timing values for desired SCL frequency
+ *
+ * @clk_rate: I2C input clock rate
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
+
+ * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
+ * a best-effort divider value is returned in divs. If the target rate is
+ * too high, we silently use the highest possible rate.
+ * The following formulas are v1's method to calculate timings.
+ *
+ * l = divl + 1;
+ * h = divh + 1;
+ * s = sda_update_config + 1;
+ * u = start_setup_config + 1;
+ * p = stop_setup_config + 1;
+ * T = Tclk_i2c;
+
+ * tHigh = 8 * h * T;
+ * tLow = 8 * l * T;
+
+ * tHD;sda = (l * s + 1) * T;
+ * tSU;sda = [(8 - s) * l + 1] * T;
+ * tI2C = 8 * (l + h) * T;
+
+ * tSU;sta = (8h * u + 1) * T;
+ * tHD;sta = [8h * (u + 1) - 1] * T;
+ * tSU;sto = (8h * p + 1) * T;
+ */
+static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
+				    struct i2c_timings *t,
+				    struct rk3x_i2c_calced_timings *t_calc)
+{
+	unsigned long min_low_ns, min_high_ns, min_total_ns;
+	unsigned long min_setup_start_ns, min_setup_data_ns;
+	unsigned long min_setup_stop_ns, max_hold_data_ns;
+
+	unsigned long clk_rate_khz, scl_rate_khz;
+
+	unsigned long min_low_div, min_high_div;
+
+	unsigned long min_div_for_hold, min_total_div;
+	unsigned long extra_div, extra_low_div;
+	unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg;
+
+	const struct i2c_spec_values *spec;
+	int ret = 0;
+
+	/* Support standard-mode and fast-mode */
+	if (WARN_ON(t->bus_freq_hz > 400000))
+		t->bus_freq_hz = 400000;
+
+	/* prevent scl_rate_khz from becoming 0 */
+	if (WARN_ON(t->bus_freq_hz < 1000))
+		t->bus_freq_hz = 1000;
+
+	/*
+	 * min_low_ns: The minimum number of ns we need to hold low to
+	 *	       meet I2C specification, should include fall time.
+	 * min_high_ns: The minimum number of ns we need to hold high to
+	 *	        meet I2C specification, should include rise time.
+	 */
+	spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+
+	/* calculate min-divh and min-divl */
+	clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
+	scl_rate_khz = t->bus_freq_hz / 1000;
+	min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
+
+	min_high_ns = t->scl_rise_ns + spec->min_high_ns;
+	min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
+
+	min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+	min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
+
+	/* Final divh and divl must be greater than 0, otherwise the
+	 * hardware would not output the i2c clk.
+	 */
+	min_high_div = (min_high_div < 1) ? 2 : min_high_div;
+	min_low_div = (min_low_div < 1) ? 2 : min_low_div;
+
+	/* These are the min dividers needed for min hold times. */
+	min_div_for_hold = (min_low_div + min_high_div);
+	min_total_ns = min_low_ns + min_high_ns;
+
+	/*
+	 * This is the maximum divider so we don't go over the maximum.
+	 * We don't round up here (we round down) since this is a maximum.
+	 */
+	 if (min_div_for_hold >= min_total_div) {
+		/*
+		 * Time needed to meet hold requirements is important.
+		 * Just use that.
+		 */
+		t_calc->div_low = min_low_div;
+		t_calc->div_high = min_high_div;
+	} else {
+		/*
+		 * We've got to distribute some time among the low and high
+		 * so we don't run too fast.
+		 * We'll try to split things up by the scale of min_low_div and
+		 * min_high_div, biasing slightly towards having a higher div
+		 * for low (spend more time low).
+		 */
+		extra_div = min_total_div - min_div_for_hold;
+		extra_low_div = DIV_ROUND_UP(min_low_div * extra_div,
+					     min_div_for_hold);
+
+		t_calc->div_low = min_low_div + extra_low_div;
+		t_calc->div_high = min_high_div + (extra_div - extra_low_div);
+	}
+
+	/*
+	 * calculate sda data hold count by the rules, data_upd_st:3
+	 * is a appropriate value to reduce calculated times.
+	 */
+	for (sda_update_cfg = 3; sda_update_cfg > 0; sda_update_cfg--) {
+		max_hold_data_ns =  DIV_ROUND_UP((sda_update_cfg
+						 * (t_calc->div_low) + 1)
+						 * 1000000, clk_rate_khz);
+		min_setup_data_ns =  DIV_ROUND_UP(((8 - sda_update_cfg)
+						 * (t_calc->div_low) + 1)
+						 * 1000000, clk_rate_khz);
+		if ((max_hold_data_ns < spec->max_data_hold_ns) &&
+		    (min_setup_data_ns > spec->min_data_setup_ns))
+			break;
+	}
+
+	/* calculate setup start config */
+	min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns;
+	stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns
+			   - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+	/* calculate setup stop config */
+	min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns;
+	stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns
+			   - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+	t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) |
+			 REG_CON_STA_CFG(--stp_sta_cfg) |
+			 REG_CON_STO_CFG(--stp_sto_cfg);
+
+	t_calc->div_low--;
+	t_calc->div_high--;
+
+	/* Maximum divider supported by hw is 0xffff */
+	if (t_calc->div_low > 0xffff) {
+		t_calc->div_low = 0xffff;
+		ret = -EINVAL;
+	}
+
+	if (t_calc->div_high > 0xffff) {
+		t_calc->div_high = 0xffff;
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 {
 	struct i2c_timings *t = &i2c->t;
-	struct rk3x_i2c_calced_timings calc;
+	struct rk3x_i2c_calced_timings *calc = &i2c->t_calc;
 	u64 t_low_ns, t_high_ns;
 	int ret;
 
-	ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
+	ret = i2c->soc_data->calc_timings(clk_rate, t, calc);
 	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
 
-	clk_enable(i2c->clk);
-	i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
+	if (i2c->pclk)
+		clk_enable(i2c->pclk);
+	else
+		clk_enable(i2c->clk);
+	i2c_writel(i2c, (calc->div_high << 16) | (calc->div_low & 0xffff),
 		   REG_CLKDIV);
-	clk_disable(i2c->clk);
+	if (i2c->pclk)
+		clk_disable(i2c->pclk);
+	else
+		clk_disable(i2c->clk);
 
-	t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
-	t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
+	t_low_ns = div_u64(((u64)calc->div_low + 1) * 8 * 1000000000, clk_rate);
+	t_high_ns = div_u64(((u64)calc->div_high + 1) * 8 * 1000000000,
 			    clk_rate);
 	dev_dbg(i2c->dev,
 		"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
@@ -728,11 +910,11 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
 {
 	struct clk_notifier_data *ndata = data;
 	struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
-	struct rk3x_i2c_calced_timings calc;
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
-		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0)
+		if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t,
+						&i2c->t_calc) != 0)
 			return NOTIFY_STOP;
 
 		/* scale up */
@@ -847,6 +1029,8 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 
 	spin_lock_irqsave(&i2c->lock, flags);
 
+	if (i2c->pclk)
+		clk_enable(i2c->pclk);
 	clk_enable(i2c->clk);
 
 	i2c->is_last_msg = false;
@@ -881,7 +1065,8 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 
 			/* Force a STOP condition without interrupt */
 			i2c_writel(i2c, 0, REG_IEN);
-			i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON);
+			i2c_writel(i2c, i2c->t_calc.tuning | REG_CON_EN |
+				   REG_CON_STOP, REG_CON);
 
 			i2c->state = STATE_IDLE;
 
@@ -896,6 +1081,8 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 	}
 
 	clk_disable(i2c->clk);
+	if (i2c->pclk)
+		clk_disable(i2c->pclk);
 	spin_unlock_irqrestore(&i2c->lock, flags);
 
 	return ret < 0 ? ret : num;
@@ -913,18 +1100,27 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
 
 static const struct rk3x_i2c_soc_data rk3066_soc_data = {
 	.grf_offset = 0x154,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3188_soc_data = {
 	.grf_offset = 0x0a4,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3228_soc_data = {
 	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3288_soc_data = {
 	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3399_soc_data = {
+	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v1_calc_timings,
 };
 
 static const struct of_device_id rk3x_i2c_match[] = {
@@ -944,6 +1140,10 @@ static const struct of_device_id rk3x_i2c_match[] = {
 		.compatible = "rockchip,rk3288-i2c",
 		.data = (void *)&rk3288_soc_data
 	},
+	{
+		.compatible = "rockchip,rk3399-i2c",
+		.data = (void *)&rk3399_soc_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
@@ -983,12 +1183,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 	spin_lock_init(&i2c->lock);
 	init_waitqueue_head(&i2c->wait);
 
-	i2c->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(i2c->clk)) {
-		dev_err(&pdev->dev, "cannot get clock\n");
-		return PTR_ERR(i2c->clk);
-	}
-
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(i2c->regs))
@@ -1042,17 +1236,38 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, i2c);
 
+	i2c->clk = devm_clk_get(&pdev->dev, NULL);
+	if (IS_ERR(i2c->clk)) {
+		dev_err(&pdev->dev, "cannot get clock\n");
+		return PTR_ERR(i2c->clk);
+	}
+
 	ret = clk_prepare(i2c->clk);
 	if (ret < 0) {
 		dev_err(&pdev->dev, "Could not prepare clock\n");
 		return ret;
 	}
 
+	if (i2c->soc_data->calc_timings == rk3x_i2c_v1_calc_timings) {
+		i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
+		if (IS_ERR(i2c->pclk)) {
+			dev_err(i2c->dev, "Could not get i2c pclk\n");
+			ret = PTR_ERR(i2c->pclk);
+			goto err_clk;
+		}
+
+		ret = clk_prepare(i2c->pclk);
+		if (ret) {
+			dev_err(i2c->dev, "Could not prepare pclk\n");
+			goto err_clk;
+		}
+	}
+
 	i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
 	ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "Unable to register clock notifier\n");
-		goto err_clk;
+		goto err_pclk;
 	}
 
 	clk_rate = clk_get_rate(i2c->clk);
@@ -1070,6 +1285,9 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 
 err_clk_notifier:
 	clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+err_pclk:
+	if (i2c->pclk)
+		clk_unprepare(i2c->pclk);
 err_clk:
 	clk_unprepare(i2c->clk);
 	return ret;
@@ -1082,6 +1300,8 @@ static int rk3x_i2c_remove(struct platform_device *pdev)
 	i2c_del_adapter(&i2c->adap);
 
 	clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+	if (i2c->pclk)
+		clk_unprepare(i2c->pclk);
 	clk_unprepare(i2c->clk);
 
 	return 0;
-- 
1.9.1




From david.wu at rock-chips.com  Wed May  4 07:37:48 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed,  4 May 2016 22:37:48 +0800
Subject: [PATCH v7 9/9] i2c: rk3x: support fast-mode plus for rk3399
In-Reply-To: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462372668-6583-1-git-send-email-david.wu@rock-chips.com>

Signed-off-by: David Wu <david.wu at rock-chips.com>
---
 drivers/i2c/busses/i2c-rk3x.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 47368c4..c66cc39 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -124,6 +124,17 @@ static const struct i2c_spec_values fast_mode_spec = {
 	.min_hold_buffer_ns = 1300,
 };
 
+static const struct i2c_spec_values fast_mode_plus_spec = {
+	.min_hold_start_ns = 260,
+	.min_low_ns = 500,
+	.min_high_ns = 260,
+	.min_setup_start_ns = 260,
+	.max_data_hold_ns = 400,
+	.min_data_setup_ns = 50,
+	.min_setup_stop_ns = 260,
+	.min_hold_buffer_ns = 500,
+};
+
 /**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
@@ -534,8 +545,10 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
 {
 	if (speed <= 100000)
 		return &standard_mode_spec;
-	else
+	else if (speed <= 400000)
 		return &fast_mode_spec;
+	else
+		return &fast_mode_plus_spec;
 }
 
 /**
@@ -746,9 +759,9 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
 	const struct i2c_spec_values *spec;
 	int ret = 0;
 
-	/* Support standard-mode and fast-mode */
-	if (WARN_ON(t->bus_freq_hz > 400000))
-		t->bus_freq_hz = 400000;
+	/* Support standard-mode, fast-mode and fast-mode plus */
+	if (WARN_ON(t->bus_freq_hz > 1000000))
+		t->bus_freq_hz = 1000000;
 
 	/* prevent scl_rate_khz from becoming 0 */
 	if (WARN_ON(t->bus_freq_hz < 1000))
-- 
1.9.1




From john at metanate.com  Wed May  4 07:54:45 2016
From: john at metanate.com (John Keeping)
Date: Wed,  4 May 2016 15:54:45 +0100
Subject: [PATCH 1/2] Revert "ASoC: rockchip: i2s: remove unused variables"
Message-ID: <1462373686-21794-1-git-send-email-john@metanate.com>

This reverts commit 5938448b99275cba95167c3f9d39ca9225fdad38.

It turns out that the commit that made these variables unused is wrong
so we're about to revert it.  Bring back the variables in prepration.

Signed-off-by: John Keeping <john at metanate.com>
---
 sound/soc/rockchip/rockchip_i2s.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 2f8e20416bd3..34743ec61c49 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -34,6 +34,13 @@ struct rk_i2s_dev {
 
 	struct regmap *regmap;
 
+/*
+ * Used to indicate the tx/rx status.
+ * I2S controller hopes to start the tx and rx together,
+ * also to stop them when they are both try to stop.
+*/
+	bool tx_start;
+	bool rx_start;
 	bool is_master_mode;
 };
 
@@ -77,7 +84,11 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_XFER,
 				   I2S_XFER_TXS_START,
 				   I2S_XFER_TXS_START);
+
+		i2s->tx_start = true;
 	} else {
+		i2s->tx_start = false;
+
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
 
@@ -115,7 +126,11 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_XFER,
 				   I2S_XFER_RXS_START,
 				   I2S_XFER_RXS_START);
+
+		i2s->rx_start = true;
 	} else {
+		i2s->rx_start = false;
+
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
 
-- 
2.8.0.rc4.238.g874082a



From john at metanate.com  Wed May  4 07:54:46 2016
From: john at metanate.com (John Keeping)
Date: Wed,  4 May 2016 15:54:46 +0100
Subject: [PATCH 2/2] Revert "ASoC: rockchip: i2s: separate capture and
 playback"
In-Reply-To: <1462373686-21794-1-git-send-email-john@metanate.com>
References: <1462373686-21794-1-git-send-email-john@metanate.com>
Message-ID: <1462373686-21794-2-git-send-email-john@metanate.com>

This reverts commit eba65d179c1149cf79e68608d452631f33d7f017.

This broke audio on Veyron Jerry Chromebooks and I now cannot reproduce
the problem I was trying to fix even with this commit reverted, so it
seems that this was completely the wrong thing to do.

Reported-by: Enric Balletbo Serra <eballetbo at gmail.com>
Signed-off-by: John Keeping <john at metanate.com>
---
 sound/soc/rockchip/rockchip_i2s.c | 72 ++++++++++++++++++++++-----------------
 1 file changed, 40 insertions(+), 32 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 34743ec61c49..574c6af28c06 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -82,8 +82,8 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
 
 		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_TXS_START,
-				   I2S_XFER_TXS_START);
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 
 		i2s->tx_start = true;
 	} else {
@@ -92,23 +92,27 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
 
-		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_TXS_START,
-				   I2S_XFER_TXS_STOP);
-
-		regmap_update_bits(i2s->regmap, I2S_CLR,
-				   I2S_CLR_TXC,
-				   I2S_CLR_TXC);
+		if (!i2s->rx_start) {
+			regmap_update_bits(i2s->regmap, I2S_XFER,
+					   I2S_XFER_TXS_START |
+					   I2S_XFER_RXS_START,
+					   I2S_XFER_TXS_STOP |
+					   I2S_XFER_RXS_STOP);
 
-		regmap_read(i2s->regmap, I2S_CLR, &val);
+			regmap_update_bits(i2s->regmap, I2S_CLR,
+					   I2S_CLR_TXC | I2S_CLR_RXC,
+					   I2S_CLR_TXC | I2S_CLR_RXC);
 
-		/* Should wait for clear operation to finish */
-		while (val & I2S_CLR_TXC) {
 			regmap_read(i2s->regmap, I2S_CLR, &val);
-			retry--;
-			if (!retry) {
-				dev_warn(i2s->dev, "fail to clear\n");
-				break;
+
+			/* Should wait for clear operation to finish */
+			while (val) {
+				regmap_read(i2s->regmap, I2S_CLR, &val);
+				retry--;
+				if (!retry) {
+					dev_warn(i2s->dev, "fail to clear\n");
+					break;
+				}
 			}
 		}
 	}
@@ -124,8 +128,8 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
 
 		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_RXS_START,
-				   I2S_XFER_RXS_START);
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 
 		i2s->rx_start = true;
 	} else {
@@ -134,23 +138,27 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
 
-		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_RXS_START,
-				   I2S_XFER_RXS_STOP);
-
-		regmap_update_bits(i2s->regmap, I2S_CLR,
-				   I2S_CLR_RXC,
-				   I2S_CLR_RXC);
+		if (!i2s->tx_start) {
+			regmap_update_bits(i2s->regmap, I2S_XFER,
+					   I2S_XFER_TXS_START |
+					   I2S_XFER_RXS_START,
+					   I2S_XFER_TXS_STOP |
+					   I2S_XFER_RXS_STOP);
 
-		regmap_read(i2s->regmap, I2S_CLR, &val);
+			regmap_update_bits(i2s->regmap, I2S_CLR,
+					   I2S_CLR_TXC | I2S_CLR_RXC,
+					   I2S_CLR_TXC | I2S_CLR_RXC);
 
-		/* Should wait for clear operation to finish */
-		while (val & I2S_CLR_RXC) {
 			regmap_read(i2s->regmap, I2S_CLR, &val);
-			retry--;
-			if (!retry) {
-				dev_warn(i2s->dev, "fail to clear\n");
-				break;
+
+			/* Should wait for clear operation to finish */
+			while (val) {
+				regmap_read(i2s->regmap, I2S_CLR, &val);
+				retry--;
+				if (!retry) {
+					dev_warn(i2s->dev, "fail to clear\n");
+					break;
+				}
 			}
 		}
 	}
-- 
2.8.0.rc4.238.g874082a



From eballetbo at gmail.com  Wed May  4 08:04:42 2016
From: eballetbo at gmail.com (Enric Balletbo Serra)
Date: Wed, 4 May 2016 17:04:42 +0200
Subject: [PATCH 1/2] Revert "ASoC: rockchip: i2s: remove unused variables"
In-Reply-To: <1462373686-21794-1-git-send-email-john@metanate.com>
References: <1462373686-21794-1-git-send-email-john@metanate.com>
Message-ID: <CAFqH_51KuNv+mypL0n5E1aOicqt+sr_S-Egm0eocrj82XF9X-w@mail.gmail.com>

Hi John,

Thanks for the patches.

2016-05-04 16:54 GMT+02:00 John Keeping <john at metanate.com>:
> This reverts commit 5938448b99275cba95167c3f9d39ca9225fdad38.
>
> It turns out that the commit that made these variables unused is wrong
> so we're about to revert it.  Bring back the variables in prepration.
>
> Signed-off-by: John Keeping <john at metanate.com>
> ---
>  sound/soc/rockchip/rockchip_i2s.c | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
>
> diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
> index 2f8e20416bd3..34743ec61c49 100644
> --- a/sound/soc/rockchip/rockchip_i2s.c
> +++ b/sound/soc/rockchip/rockchip_i2s.c
> @@ -34,6 +34,13 @@ struct rk_i2s_dev {
>
>         struct regmap *regmap;
>
> +/*
> + * Used to indicate the tx/rx status.
> + * I2S controller hopes to start the tx and rx together,
> + * also to stop them when they are both try to stop.
> +*/
> +       bool tx_start;
> +       bool rx_start;
>         bool is_master_mode;
>  };
>
> @@ -77,7 +84,11 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
>                 regmap_update_bits(i2s->regmap, I2S_XFER,
>                                    I2S_XFER_TXS_START,
>                                    I2S_XFER_TXS_START);
> +
> +               i2s->tx_start = true;
>         } else {
> +               i2s->tx_start = false;
> +
>                 regmap_update_bits(i2s->regmap, I2S_DMACR,
>                                    I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
>
> @@ -115,7 +126,11 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
>                 regmap_update_bits(i2s->regmap, I2S_XFER,
>                                    I2S_XFER_RXS_START,
>                                    I2S_XFER_RXS_START);
> +
> +               i2s->rx_start = true;
>         } else {
> +               i2s->rx_start = false;
> +
>                 regmap_update_bits(i2s->regmap, I2S_DMACR,
>                                    I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
>
> --
> 2.8.0.rc4.238.g874082a
>

Apart from these two patches, to get audio working on Veyron device
I've some other fixes, If it's ok I would like to include these
patches into my series, so we have a patch series that fixes the audio
for veyron.

Best regards,
 Enric


From broonie at kernel.org  Wed May  4 08:10:28 2016
From: broonie at kernel.org (Mark Brown)
Date: Wed, 4 May 2016 16:10:28 +0100
Subject: [PATCH 1/2] Revert "ASoC: rockchip: i2s: remove unused variables"
In-Reply-To: <1462373686-21794-1-git-send-email-john@metanate.com>
References: <1462373686-21794-1-git-send-email-john@metanate.com>
Message-ID: <20160504151028.GW6292@sirena.org.uk>

On Wed, May 04, 2016 at 03:54:45PM +0100, John Keeping wrote:
> This reverts commit 5938448b99275cba95167c3f9d39ca9225fdad38.
> 
> It turns out that the commit that made these variables unused is wrong
> so we're about to revert it.  Bring back the variables in prepration.

Please submit patches using subject lines reflecting the style for the
subsystem.  This makes it easier for people to identify relevant
patches.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160504/532607aa/attachment.sig>

From john at metanate.com  Wed May  4 09:21:57 2016
From: john at metanate.com (John Keeping)
Date: Wed,  4 May 2016 17:21:57 +0100
Subject: [PATCH v2 2/2] ASoC: rockchip: Revert "ASoC: rockchip: i2s: separate
 capture and playback"
In-Reply-To: <1462378917-24135-1-git-send-email-john@metanate.com>
References: <1462378917-24135-1-git-send-email-john@metanate.com>
Message-ID: <1462378917-24135-2-git-send-email-john@metanate.com>

This reverts commit eba65d179c1149cf79e68608d452631f33d7f017.

This broke audio on Veyron Jerry Chromebooks and I now cannot reproduce
the problem I was trying to fix even with this commit reverted, so it
seems that this was completely the wrong thing to do.

Reported-by: Enric Balletbo Serra <eballetbo at gmail.com>
Signed-off-by: John Keeping <john at metanate.com>
---
v2: Add "ASoC: rockchip: " prefix to subject

 sound/soc/rockchip/rockchip_i2s.c | 72 ++++++++++++++++++++++-----------------
 1 file changed, 40 insertions(+), 32 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 34743ec61c49..574c6af28c06 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -82,8 +82,8 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
 
 		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_TXS_START,
-				   I2S_XFER_TXS_START);
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 
 		i2s->tx_start = true;
 	} else {
@@ -92,23 +92,27 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
 
-		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_TXS_START,
-				   I2S_XFER_TXS_STOP);
-
-		regmap_update_bits(i2s->regmap, I2S_CLR,
-				   I2S_CLR_TXC,
-				   I2S_CLR_TXC);
+		if (!i2s->rx_start) {
+			regmap_update_bits(i2s->regmap, I2S_XFER,
+					   I2S_XFER_TXS_START |
+					   I2S_XFER_RXS_START,
+					   I2S_XFER_TXS_STOP |
+					   I2S_XFER_RXS_STOP);
 
-		regmap_read(i2s->regmap, I2S_CLR, &val);
+			regmap_update_bits(i2s->regmap, I2S_CLR,
+					   I2S_CLR_TXC | I2S_CLR_RXC,
+					   I2S_CLR_TXC | I2S_CLR_RXC);
 
-		/* Should wait for clear operation to finish */
-		while (val & I2S_CLR_TXC) {
 			regmap_read(i2s->regmap, I2S_CLR, &val);
-			retry--;
-			if (!retry) {
-				dev_warn(i2s->dev, "fail to clear\n");
-				break;
+
+			/* Should wait for clear operation to finish */
+			while (val) {
+				regmap_read(i2s->regmap, I2S_CLR, &val);
+				retry--;
+				if (!retry) {
+					dev_warn(i2s->dev, "fail to clear\n");
+					break;
+				}
 			}
 		}
 	}
@@ -124,8 +128,8 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
 
 		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_RXS_START,
-				   I2S_XFER_RXS_START);
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 
 		i2s->rx_start = true;
 	} else {
@@ -134,23 +138,27 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
 
-		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_RXS_START,
-				   I2S_XFER_RXS_STOP);
-
-		regmap_update_bits(i2s->regmap, I2S_CLR,
-				   I2S_CLR_RXC,
-				   I2S_CLR_RXC);
+		if (!i2s->tx_start) {
+			regmap_update_bits(i2s->regmap, I2S_XFER,
+					   I2S_XFER_TXS_START |
+					   I2S_XFER_RXS_START,
+					   I2S_XFER_TXS_STOP |
+					   I2S_XFER_RXS_STOP);
 
-		regmap_read(i2s->regmap, I2S_CLR, &val);
+			regmap_update_bits(i2s->regmap, I2S_CLR,
+					   I2S_CLR_TXC | I2S_CLR_RXC,
+					   I2S_CLR_TXC | I2S_CLR_RXC);
 
-		/* Should wait for clear operation to finish */
-		while (val & I2S_CLR_RXC) {
 			regmap_read(i2s->regmap, I2S_CLR, &val);
-			retry--;
-			if (!retry) {
-				dev_warn(i2s->dev, "fail to clear\n");
-				break;
+
+			/* Should wait for clear operation to finish */
+			while (val) {
+				regmap_read(i2s->regmap, I2S_CLR, &val);
+				retry--;
+				if (!retry) {
+					dev_warn(i2s->dev, "fail to clear\n");
+					break;
+				}
 			}
 		}
 	}
-- 
2.8.0.rc4.238.g874082a



From john at metanate.com  Wed May  4 09:21:56 2016
From: john at metanate.com (John Keeping)
Date: Wed,  4 May 2016 17:21:56 +0100
Subject: [PATCH v2 1/2] ASoC: rockchip: Revert "ASoC: rockchip: i2s: remove
 unused variables"
Message-ID: <1462378917-24135-1-git-send-email-john@metanate.com>

This reverts commit 5938448b99275cba95167c3f9d39ca9225fdad38.

It turns out that the commit that made these variables unused is wrong
so we're about to revert it.  Bring back the variables in prepration.

Signed-off-by: John Keeping <john at metanate.com>
---
v2: Add "ASoC: rockchip: " prefix to subject

 sound/soc/rockchip/rockchip_i2s.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 2f8e20416bd3..34743ec61c49 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -34,6 +34,13 @@ struct rk_i2s_dev {
 
 	struct regmap *regmap;
 
+/*
+ * Used to indicate the tx/rx status.
+ * I2S controller hopes to start the tx and rx together,
+ * also to stop them when they are both try to stop.
+*/
+	bool tx_start;
+	bool rx_start;
 	bool is_master_mode;
 };
 
@@ -77,7 +84,11 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_XFER,
 				   I2S_XFER_TXS_START,
 				   I2S_XFER_TXS_START);
+
+		i2s->tx_start = true;
 	} else {
+		i2s->tx_start = false;
+
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
 
@@ -115,7 +126,11 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_XFER,
 				   I2S_XFER_RXS_START,
 				   I2S_XFER_RXS_START);
+
+		i2s->rx_start = true;
 	} else {
+		i2s->rx_start = false;
+
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
 
-- 
2.8.0.rc4.238.g874082a



From dianders at chromium.org  Wed May  4 16:36:25 2016
From: dianders at chromium.org (Douglas Anderson)
Date: Wed,  4 May 2016 16:36:25 -0700
Subject: [PATCH] clk: rockchip: fix the rk3399 sdmmc sample / drv name
Message-ID: <1462404985-27957-1-git-send-email-dianders@chromium.org>

The rk3399 clock table had a simple typo in it, calling the SDMMC sample
and drive clocks by the wrong name.  Fix this minor typo.

Signed-off-by: Douglas Anderson <dianders at chromium.org>
---
 drivers/clk/rockchip/clk-rk3399.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
index 5248726af86d..291543f52caa 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -894,8 +894,8 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
 			RK3399_CLKSEL_CON(16), 8, 3, MFLAGS, 0, 7, DFLAGS,
 			RK3399_CLKGATE_CON(6), 1, GFLAGS),
 
-	MMC(SCLK_SDMMC_DRV,     "emmc_drv",    "clk_sdmmc", RK3399_SDMMC_CON0, 1),
-	MMC(SCLK_SDMMC_SAMPLE,  "emmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1),
+	MMC(SCLK_SDMMC_DRV,     "sdmmc_drv",    "clk_sdmmc", RK3399_SDMMC_CON0, 1),
+	MMC(SCLK_SDMMC_SAMPLE,  "sdmmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1),
 
 	MMC(SCLK_SDIO_DRV,      "sdio_drv",    "clk_sdio",  RK3399_SDIO_CON0,  1),
 	MMC(SCLK_SDIO_SAMPLE,   "sdio_sample", "clk_sdio",  RK3399_SDIO_CON1,  1),
-- 
2.8.0.rc3.226.g39d4020



From dianders at chromium.org  Wed May  4 16:45:59 2016
From: dianders at chromium.org (Doug Anderson)
Date: Wed, 4 May 2016 16:45:59 -0700
Subject: [PATCH v7 1/9] i2c: rk3x: add documentation to fields in "struct
 rk3x_i2c"
In-Reply-To: <1462371194-5809-2-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462371194-5809-2-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=VyAie7NcO3q4qQWEdHaiUUHbRN-6iWV3y+kvgSYPpkEg@mail.gmail.com>

David,

On Wed, May 4, 2016 at 7:13 AM, David Wu <david.wu at rock-chips.com> wrote:
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> ---
> Change in v7:
> - none
>
>  drivers/i2c/busses/i2c-rk3x.c | 22 +++++++++++++++++++++-
>  1 file changed, 21 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
> index 80bed02..7e45d51 100644
> --- a/drivers/i2c/busses/i2c-rk3x.c
> +++ b/drivers/i2c/busses/i2c-rk3x.c
> @@ -90,6 +90,26 @@ struct rk3x_i2c_soc_data {
>         int grf_offset;
>  };
>
> +/**
> + * struct rk3x_i2c - private data of the controller
> + * @adap: corresponding I2C adapter
> + * @dev: device for this controller
> + * @soc_data: related soc data struct
> + * @regs: virtual memory area
> + * @clk: clock of i2c bus
> + * @clk_rate_nb: i2c clk rate change notify
> + * @t: I2C known timing information

You're a little ahead of yourself.  The @t element doesn't exist as of
this patch.  Instead all the sub-elements are there.  This in this
patch you need to document scl_frequency, scl_rise_ns, ....  In a
later patch you'd change it to t.


-Doug


From dianders at chromium.org  Wed May  4 16:50:25 2016
From: dianders at chromium.org (Doug Anderson)
Date: Wed, 4 May 2016 16:50:25 -0700
Subject: [PATCH v7 1/9] i2c: rk3x: add documentation to fields in "struct
 rk3x_i2c"
In-Reply-To: <CAD=FV=VyAie7NcO3q4qQWEdHaiUUHbRN-6iWV3y+kvgSYPpkEg@mail.gmail.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462371194-5809-2-git-send-email-david.wu@rock-chips.com>
 <CAD=FV=VyAie7NcO3q4qQWEdHaiUUHbRN-6iWV3y+kvgSYPpkEg@mail.gmail.com>
Message-ID: <CAD=FV=VUaq6-_NNy-K2BrTDHY1pzJGA6wGtPTvc8H1ABgDqf0w@mail.gmail.com>

David,

On Wed, May 4, 2016 at 4:45 PM, Doug Anderson <dianders at chromium.org> wrote:
> David,
>
> On Wed, May 4, 2016 at 7:13 AM, David Wu <david.wu at rock-chips.com> wrote:
>> Signed-off-by: David Wu <david.wu at rock-chips.com>
>> ---
>> Change in v7:
>> - none
>>
>>  drivers/i2c/busses/i2c-rk3x.c | 22 +++++++++++++++++++++-
>>  1 file changed, 21 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
>> index 80bed02..7e45d51 100644
>> --- a/drivers/i2c/busses/i2c-rk3x.c
>> +++ b/drivers/i2c/busses/i2c-rk3x.c
>> @@ -90,6 +90,26 @@ struct rk3x_i2c_soc_data {
>>         int grf_offset;
>>  };
>>
>> +/**
>> + * struct rk3x_i2c - private data of the controller
>> + * @adap: corresponding I2C adapter
>> + * @dev: device for this controller
>> + * @soc_data: related soc data struct
>> + * @regs: virtual memory area
>> + * @clk: clock of i2c bus
>> + * @clk_rate_nb: i2c clk rate change notify
>> + * @t: I2C known timing information
>
> You're a little ahead of yourself.  The @t element doesn't exist as of
> this patch.  Instead all the sub-elements are there.  This in this
> patch you need to document scl_frequency, scl_rise_ns, ....  In a
> later patch you'd change it to t.

Or I'm an idiot and applied to the wrong branch.  Your patch is fine.

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From briannorris at chromium.org  Wed May  4 18:11:12 2016
From: briannorris at chromium.org (Brian Norris)
Date: Wed, 4 May 2016 18:11:12 -0700
Subject: [PATCH] ARM: dts: rockchip: move rk3288 edp phy under the GRF
In-Reply-To: <4275673.EbRsbqkhH8@diego>
References: <1640976.sZtsTTlDpl@diego>
 <4275673.EbRsbqkhH8@diego>
Message-ID: <20160505011112.GA131923@google.com>

On Fri, Apr 22, 2016 at 03:56:27PM +0200, Heiko Stuebner wrote:
> Am Samstag, 16. April 2016, 02:49:14 schrieb Heiko St?bner:
> > The edp-phy control is a part of the General Register Files and
> > with a recent patch in 4.6 the phy driver can now also handle this
> > correctly, so move the dts node under the GRF as well.
> > 
> > Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> 
> the change in the phy-driver has made it into Greg's usb tree as fix for 4.6, 
> so I've picked this patch for 4.7 now.

Not sure if it's intentional, but the phy binding change (which is in
4.6) broke the DP support in 4.6/rk3288.dtsi, and this patch is
necessary to bring it back. Shouldn't this DTS change have gone to 4.7
too? Or (when convincing ourselves we're not breaking the DT ABI here),
could we just claim that eDP wasn't supported in 4.6, and 4.7 will just
be bug-fixing the rk3288 DTS?

Brian


From briannorris at chromium.org  Wed May  4 18:16:21 2016
From: briannorris at chromium.org (Brian Norris)
Date: Wed, 4 May 2016 18:16:21 -0700
Subject: [PATCH] ARM: dts: rockchip: move rk3288 edp phy under the GRF
In-Reply-To: <20160505011112.GA131923@google.com>
References: <1640976.sZtsTTlDpl@diego> <4275673.EbRsbqkhH8@diego>
 <20160505011112.GA131923@google.com>
Message-ID: <20160505011621.GA44327@google.com>

On Wed, May 04, 2016 at 06:11:12PM -0700, Brian Norris wrote:
> On Fri, Apr 22, 2016 at 03:56:27PM +0200, Heiko Stuebner wrote:
> > Am Samstag, 16. April 2016, 02:49:14 schrieb Heiko St?bner:
> > > The edp-phy control is a part of the General Register Files and
> > > with a recent patch in 4.6 the phy driver can now also handle this
> > > correctly, so move the dts node under the GRF as well.
> > > 
> > > Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> > 
> > the change in the phy-driver has made it into Greg's usb tree as fix for 4.6, 
> > so I've picked this patch for 4.7 now.
> 
> Not sure if it's intentional, but the phy binding change (which is in
> 4.6) broke the DP support in 4.6/rk3288.dtsi, and this patch is
> necessary to bring it back. Shouldn't this DTS change have gone to 4.7
> too? Or (when convincing ourselves we're not breaking the DT ABI here),
> could we just claim that eDP wasn't supported in 4.6, and 4.7 will just
> be bug-fixing the rk3288 DTS?

Oops, my bad. The eDP PHY didn't show up at all in the v4.6/rk3288.dtsi.
So no breakage. Sorry for the false alarm.

Brian


From shawn.lin at rock-chips.com  Wed May  4 19:16:31 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 5 May 2016 10:16:31 +0800
Subject: [PATCH v2 3/6] mmc: core: implement enhanced strobe support
In-Reply-To: <CAPDyKFogNjwNs+fKPaah_X=AfSgtXUwefzon+ZQ2a2Va5Om5Nw@mail.gmail.com>
References: <1461897751-28810-1-git-send-email-shawn.lin@rock-chips.com>
 <1461898029-28944-1-git-send-email-shawn.lin@rock-chips.com>
 <CAPDyKFogNjwNs+fKPaah_X=AfSgtXUwefzon+ZQ2a2Va5Om5Nw@mail.gmail.com>
Message-ID: <58a0a7b5-5cf2-3c34-9613-d22e01a0f2ab@rock-chips.com>

On 2016/5/4 20:02, Ulf Hansson wrote:
> On 29 April 2016 at 04:47, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> Controllers use data strobe line to latch data from devices
>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>> introduces enhanced strobe mode for latching cmd response from
>> emmc devices to host controllers. This new feature is optional,
>> so it depends both on device's cap and host's cap to decide
>> whether to use it or not.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> ---
>>
>> Changes in v2: None
>>
>>  drivers/mmc/core/bus.c   |  3 +-
>>  drivers/mmc/core/mmc.c   | 77 ++++++++++++++++++++++++++++++++++++++++++++----
>>  include/linux/mmc/card.h |  1 +
>>  include/linux/mmc/host.h | 12 ++++++++
>>  include/linux/mmc/mmc.h  |  3 ++
>>  5 files changed, 89 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> index 4bc48f1..7e94b9d 100644
>> --- a/drivers/mmc/core/bus.c
>> +++ b/drivers/mmc/core/bus.c
>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>                         mmc_card_ddr52(card) ? "DDR " : "",
>>                         type);
>>         } else {
>> -               pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>> +               pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>                         mmc_hostname(card->host),
>>                         mmc_card_uhs(card) ? "ultra high speed " :
>>                         (mmc_card_hs(card) ? "high speed " : ""),
>>                         mmc_card_hs400(card) ? "HS400 " :
>>                         (mmc_card_hs200(card) ? "HS200 " : ""),
>> +                       mmc_card_hs400es(card) ? "Enhanced strobe" : "",
>
> I am not sure this informations should be printed. It's still and
> HS400 card, there is no performance impact, right?

Just as Adrain said, a significant behaviour for hs400es is that
it doesn't need tuning/re-tune stuff. So I prone to keep it here.

>
>>                         mmc_card_ddr52(card) ? "DDR " : "",
>>                         uhs_bus_speed_mode, type, card->rca);
>>         }
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index 28b477d..f45ed10 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -235,6 +235,12 @@ static void mmc_select_card_type(struct mmc_card *card)
>>                 avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>>         }
>>
>> +       if ((caps2 & MMC_CAP2_HS400_ENHANCED_STROBE) &&
>> +           card->ext_csd.strobe_support &&
>> +           ((card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) ||
>> +            (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)))
>> +               avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
>> +
>>         card->ext_csd.hs_max_dtr = hs_max_dtr;
>>         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>>         card->mmc_avail_type = avail_type;
>> @@ -383,6 +389,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>                         mmc_card_set_blockaddr(card);
>>         }
>>
>> +       card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>>         card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>         mmc_select_card_type(card);
>>
>> @@ -1062,9 +1069,10 @@ static int mmc_select_hs400(struct mmc_card *card)
>>         u8 val;
>>
>>         /*
>> -        * HS400 mode requires 8-bit bus width
>> +        * HS400(ES) mode requires 8-bit bus width
>>          */
>> -       if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
>> +       if (!(((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400) ||
>> +               (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)) &&
>>               host->ios.bus_width == MMC_BUS_WIDTH_8))
>>                 return 0;
>>
>> @@ -1097,9 +1105,26 @@ static int mmc_select_hs400(struct mmc_card *card)
>>         }
>>
>>         /* Switch card to DDR */
>> +       val = EXT_CSD_DDR_BUS_WIDTH_8;
>> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
>> +               val |= EXT_CSD_BUS_WIDTH_STROBE;
>> +               /*
>> +               * Make sure we are in non-enhanced strobe mode before we
>> +               * actually enable it in ext_csd.
>> +               */
>> +               if (host->ops->prepare_enhanced_strobe)
>> +                       err = host->ops->prepare_enhanced_strobe(host, false);
>
> 1) I suggest we rename the callback to "hs400_enhanced_strobe".

Aha, personal taste?
I'm ok for whatever the name to be :)

>
> 2) I think this might be is a bit late to deal with restoring enhanced
> strobe to off. Perhaps we should do that in mmc_set_initial_state()
> instead!?
>

Good idea.

>> +
>> +               if (err) {
>> +                       pr_err("%s: unprepare_enhanced strobe failed, err:%d\n",
>
> Maybe pr_dbg instead?
>
> /s/unprepare_enhanced strobe/Disable hs400 es

ok, most of the failure in mmc_init_card use
pr_warn/dbg.

So will fix it.

>
>> +                               mmc_hostname(host), err);
>> +                       return err;
>> +               }
>> +       }
>> +
>>         err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>                          EXT_CSD_BUS_WIDTH,
>> -                        EXT_CSD_DDR_BUS_WIDTH_8,
>> +                        val,
>>                          card->ext_csd.generic_cmd6_time);
>>         if (err) {
>>                 pr_err("%s: switch to bus width for hs400 failed, err:%d\n",
>> @@ -1124,6 +1149,35 @@ static int mmc_select_hs400(struct mmc_card *card)
>>         mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>>         mmc_set_bus_speed(card);
>>
>> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
>> +               /* Controller enable enhanced strobe function */
>> +               if (host->ops->prepare_enhanced_strobe)
>> +                       err = host->ops->prepare_enhanced_strobe(host, true);
>> +
>> +               if (err) {
>> +                       pr_err("%s: prepare enhanced strobe failed, err:%d\n",
>
> Maybe pr_dbg/warn instead?
>
> /s/prepare enhanced strobe/Enable hs400 es
>
>> +                               mmc_hostname(host), err);
>> +                       return err;
>> +               }
>> +
>> +               /*
>> +                * After switching to hs400 enhanced strobe mode, we expect to
>> +                * verify whether it works or not. If controller can't handle
>> +                * bus width test, compare ext_csd previously read in 1 bit mode
>> +                * against ext_csd at new bus width
>> +                */
>
> Is this according to spec? If so, we should probably state that here.
> If not, further explanation for *why* we do this is needed.

It's NOT from spec. Just like switch bus width, enabling enhanced strobe
brings different IO-interface timing, so I add this check to make sure
both the device and host to be ok under hs400es, otherwise we show
hs400es successfully but failing to read superblock later if mounted.

So check it in advanced is probably sane?

>
>> +               if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
>> +                       err = mmc_compare_ext_csds(card, MMC_BUS_WIDTH_8);
>> +               else
>> +                       err = mmc_bus_test(card, MMC_BUS_WIDTH_8);
>> +
>> +               if (err) {
>> +                       pr_warn("%s: switch to enhanced strobe failed\n",
>> +                               mmc_hostname(host));
>> +                       return err;
>> +               }
>> +       }
>> +
>>         if (!send_status) {
>>                 err = mmc_switch_status(card);
>>                 if (err)
>> @@ -1297,7 +1351,8 @@ err:
>>  }
>>
>>  /*
>> - * Activate High Speed or HS200 mode if supported.
>> + * Activate High Speed or HS200 mode if supported. For HS400
>> + * with enhanced strobe mode, we should activate High Speed.
>>   */
>>  static int mmc_select_timing(struct mmc_card *card)
>>  {
>> @@ -1306,7 +1361,9 @@ static int mmc_select_timing(struct mmc_card *card)
>>         if (!mmc_can_ext_csd(card))
>>                 goto bus_speed;
>>
>> -       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
>> +               err = mmc_select_hs(card);
>> +       else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>                 err = mmc_select_hs200(card);
>>         else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>                 err = mmc_select_hs(card);
>> @@ -1578,7 +1635,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>         } else if (mmc_card_hs(card)) {
>>                 /* Select the desired bus width optionally */
>>                 err = mmc_select_bus_width(card);
>> -               if (!IS_ERR_VALUE(err)) {
>> +               if (IS_ERR_VALUE(err))
>> +                       goto free_card;
>
> This is going to change the behaviour, as earlier switching the bus
> width was optional. See the comment a few lines above and the
> implementation of mmc_select_bus_width().

Sorry, but I cannot see any behavioural change for bus width.
before swithing to HS400, we should make sure it's in 8-bit mode.

Before this change, the path seems to be:
(1) select_timing : hs200 --> mmc_select_hs200 -> mmc_select_bus_width
		    hs --> mmc_select_hs
(2) mmc_card_hs200 -> tuning --> mmc_select_hs400
     mmc_card_hs -> mmc_select_bus_width -> mmc_select_hs_ddr

Now the behaviour should be:
(1) select_timing : hs400es -> mmc_select_hs
		    hs200 --> mmc_select_hs200 -> mmc_select_bus_width
		    hs --> mmc_select_hs
(2) mmc_card_hs200 -> tuning --> mmc_select_hs400
     mmc_card_hs -> mmc_select_bus_width |-> mmc_select_hs_ddr
					|-> mmc_select_hs400

did I miss something?

Thanks.

>
>> +
>> +               if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
>> +                       /* Directly from HS to HS400-ES */
>> +                       err = mmc_select_hs400(card);
>> +                       if (err)
>> +                               goto free_card;
>> +               } else {
>>                         err = mmc_select_hs_ddr(card);
>>                         if (err)
>>                                 goto free_card;
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index eb0151b..22defc2 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>>         u8                      raw_partition_support;  /* 160 */
>>         u8                      raw_rpmb_size_mult;     /* 168 */
>>         u8                      raw_erased_mem_count;   /* 181 */
>> +       u8                      strobe_support;         /* 184 */
>>         u8                      raw_ext_csd_structure;  /* 194 */
>>         u8                      raw_card_type;          /* 196 */
>>         u8                      raw_driver_strength;    /* 197 */
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index 11e89d3..19de56c 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -19,6 +19,7 @@
>>
>>  #include <linux/mmc/core.h>
>>  #include <linux/mmc/card.h>
>> +#include <linux/mmc/mmc.h>
>>  #include <linux/mmc/pm.h>
>>
>>  struct mmc_ios {
>> @@ -143,6 +144,8 @@ struct mmc_host_ops {
>>
>>         /* Prepare HS400 target operating frequency depending host driver */
>>         int     (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>> +       /* Prepare enhanced strobe depending host driver */
>> +       int     (*prepare_enhanced_strobe)(struct mmc_host *host, bool enable);
>>         int     (*select_drive_strength)(struct mmc_card *card,
>>                                          unsigned int max_dtr, int host_drv,
>>                                          int card_drv, int *drv_type);
>> @@ -518,6 +521,15 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>>         return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>>  }
>>
>> +static inline bool mmc_card_hs400es(struct mmc_card *card)
>> +{
>> +       if (mmc_card_hs400(card) &&
>> +           (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES))
>> +               return 1;
>> +
>> +       return 0;
>> +}
>> +
>>  void mmc_retune_timer_stop(struct mmc_host *host);
>>
>>  static inline void mmc_retune_needed(struct mmc_host *host)
>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> index 15f2c4a..c376209 100644
>> --- a/include/linux/mmc/mmc.h
>> +++ b/include/linux/mmc/mmc.h
>> @@ -297,6 +297,7 @@ struct _mmc_csd {
>>  #define EXT_CSD_PART_CONFIG            179     /* R/W */
>>  #define EXT_CSD_ERASED_MEM_CONT                181     /* RO */
>>  #define EXT_CSD_BUS_WIDTH              183     /* R/W */
>> +#define EXT_CSD_STROBE_SUPPORT         184     /* RO */
>>  #define EXT_CSD_HS_TIMING              185     /* R/W */
>>  #define EXT_CSD_POWER_CLASS            187     /* R/W */
>>  #define EXT_CSD_REV                    192     /* RO */
>> @@ -380,12 +381,14 @@ struct _mmc_csd {
>>  #define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<7)  /* Card can run at 200MHz DDR, 1.2V */
>>  #define EXT_CSD_CARD_TYPE_HS400                (EXT_CSD_CARD_TYPE_HS400_1_8V | \
>>                                          EXT_CSD_CARD_TYPE_HS400_1_2V)
>> +#define EXT_CSD_CARD_TYPE_HS400ES      (1<<8)  /* Card can run at HS400ES */
>>
>>  #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_8    2       /* Card is in 8 bit mode */
>>  #define EXT_CSD_DDR_BUS_WIDTH_4        5       /* Card is in 4 bit DDR mode */
>>  #define EXT_CSD_DDR_BUS_WIDTH_8        6       /* Card is in 8 bit DDR mode */
>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)        /* Enhanced strobe mode */
>>
>>  #define EXT_CSD_TIMING_BC      0       /* Backwards compatility */
>>  #define EXT_CSD_TIMING_HS      1       /* High speed */
>> --
>> 2.3.7
>>
>>
>
> Kind regards
> Uffe
>
>
>


-- 
Best Regards
Shawn Lin



From enric.balletbo at collabora.com  Thu May  5 01:03:34 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Thu,  5 May 2016 10:03:34 +0200
Subject: [PATCH 0/7] ASoC: rockchip: Fix audio on Veyron.
Message-ID: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>

Hi all,

This patch series adds support and fixes the audio support for Veyron
devices. With these patches I'm able to playback from speakers and
headphones, and record from the microphone on a Veyron Jerry Chromebook.

Patches 1/7 and 2/7 were already sent by John Keeping,[1] [2], but I
think it's interesting have them included here.

Patches from 1/7 to 5/7 should go through the Mark Brown ASoC tree.

Patches 6/7 and 7/7 should go through the Heiko Stuebner rockchip tree.

[1] https://patchwork.kernel.org/patch/9017491/
[2] https://patchwork.kernel.org/patch/9017501/

Enric Balletbo i Serra (5):
  ASoC: rockchip-max98090: Fix NULL pointer de reference while accessing
    to jack
  ASoC: rockchip-max98090: Fix the Headset Mic route.
  ASoC: rockchip-max98090: Fix DAPM unknown pin for Headset Jack
  ARM: dts: rockchip: Add shared file for audio related nodes for veyron
    boards
  ARM: dts: rockchip: veyron: Add analog audio codecs.

John Keeping (2):
  ASoC: rockchip: Revert "ASoC: rockchip: i2s: remove unused variables"
  ASoC: rockchip: Revert "ASoC: rockchip: i2s: separate capture and
    playback"

 arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi | 102 ++++++++++++++++++++++
 arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi   |   1 +
 sound/soc/rockchip/rockchip_i2s.c                 |  87 +++++++++++-------
 sound/soc/rockchip/rockchip_max98090.c            |  54 ++++++------
 4 files changed, 187 insertions(+), 57 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi

-- 
2.1.0



From enric.balletbo at collabora.com  Thu May  5 01:03:37 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Thu,  5 May 2016 10:03:37 +0200
Subject: [PATCH 3/7] ASoC: rockchip-max98090: Fix NULL pointer de reference
 while accessing to jack
In-Reply-To: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
References: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462435421-21205-4-git-send-email-enric.balletbo@collabora.com>

Since commit f2ed6b07645e ("ASoC: Make aux_dev more like a generic
component") a kernel Oops is seen. What causes the crash is the chain

 rk_98090_headset_init
   -> ts3a227e_enable_jack_detect
      -> snd_jack_set_key
 rk_init
   -> snd_soc_card_jack_new

The above commit moves the new jack object creation from rk_init to
rk_98090_headset_init function making sure jack is accessed after it's
created.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
---
 sound/soc/rockchip/rockchip_max98090.c | 50 ++++++++++++++++++----------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index 5436102..abb64a5 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -114,43 +114,27 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static int rk_init(struct snd_soc_pcm_runtime *runtime)
-{
-	/* Enable Headset and 4 Buttons Jack detection */
-	return snd_soc_card_jack_new(runtime->card, "Headset Jack",
-			       SND_JACK_HEADSET |
-			       SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-			       SND_JACK_BTN_2 | SND_JACK_BTN_3,
-			       &headset_jack,
-			       headset_jack_pins,
-			       ARRAY_SIZE(headset_jack_pins));
-}
-
-static int rk_98090_headset_init(struct snd_soc_component *component)
-{
-	return ts3a227e_enable_jack_detect(component, &headset_jack);
-}
-
 static struct snd_soc_ops rk_aif1_ops = {
 	.hw_params = rk_aif1_hw_params,
 };
 
-static struct snd_soc_aux_dev rk_98090_headset_dev = {
-	.name = "Headset Chip",
-	.init = rk_98090_headset_init,
-};
-
 static struct snd_soc_dai_link rk_dailink = {
 	.name = "max98090",
 	.stream_name = "Audio",
 	.codec_dai_name = "HiFi",
-	.init = rk_init,
 	.ops = &rk_aif1_ops,
 	/* set max98090 as slave */
 	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 		SND_SOC_DAIFMT_CBS_CFS,
 };
 
+static int rk_98090_headset_init(struct snd_soc_component *component);
+
+static struct snd_soc_aux_dev rk_98090_headset_dev = {
+	.name = "Headset Chip",
+	.init = rk_98090_headset_init,
+};
+
 static struct snd_soc_card snd_soc_card_rk = {
 	.name = "ROCKCHIP-I2S",
 	.owner = THIS_MODULE,
@@ -166,6 +150,26 @@ static struct snd_soc_card snd_soc_card_rk = {
 	.num_controls = ARRAY_SIZE(rk_mc_controls),
 };
 
+static int rk_98090_headset_init(struct snd_soc_component *component)
+{
+	int ret;
+
+	/* Enable Headset and 4 Buttons Jack detection */
+	ret = snd_soc_card_jack_new(&snd_soc_card_rk, "Headset Jack",
+				    SND_JACK_HEADSET |
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
+				    &headset_jack,
+				    headset_jack_pins,
+				    ARRAY_SIZE(headset_jack_pins));
+	if (ret)
+		return ret;
+
+	ret = ts3a227e_enable_jack_detect(component, &headset_jack);
+
+	return ret;
+}
+
 static int snd_rk_mc_probe(struct platform_device *pdev)
 {
 	int ret = 0;
-- 
2.1.0



From enric.balletbo at collabora.com  Thu May  5 01:03:35 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Thu,  5 May 2016 10:03:35 +0200
Subject: [PATCH 1/7] ASoC: rockchip: Revert "ASoC: rockchip: i2s: remove
 unused variables"
In-Reply-To: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
References: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462435421-21205-2-git-send-email-enric.balletbo@collabora.com>

From: John Keeping <john at metanate.com>

This reverts commit 5938448b99275cba95167c3f9d39ca9225fdad38.

It turns out that the commit that made these variables unused is wrong
so we're about to revert it.  Bring back the variables in prepration.

Signed-off-by: John Keeping <john at metanate.com>
Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
---
 sound/soc/rockchip/rockchip_i2s.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 2f8e204..34743ec 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -34,6 +34,13 @@ struct rk_i2s_dev {
 
 	struct regmap *regmap;
 
+/*
+ * Used to indicate the tx/rx status.
+ * I2S controller hopes to start the tx and rx together,
+ * also to stop them when they are both try to stop.
+*/
+	bool tx_start;
+	bool rx_start;
 	bool is_master_mode;
 };
 
@@ -77,7 +84,11 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_XFER,
 				   I2S_XFER_TXS_START,
 				   I2S_XFER_TXS_START);
+
+		i2s->tx_start = true;
 	} else {
+		i2s->tx_start = false;
+
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
 
@@ -115,7 +126,11 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_XFER,
 				   I2S_XFER_RXS_START,
 				   I2S_XFER_RXS_START);
+
+		i2s->rx_start = true;
 	} else {
+		i2s->rx_start = false;
+
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
 
-- 
2.1.0



From enric.balletbo at collabora.com  Thu May  5 01:03:38 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Thu,  5 May 2016 10:03:38 +0200
Subject: [PATCH 4/7] ASoC: rockchip-max98090: Fix the Headset Mic route.
In-Reply-To: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
References: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462435421-21205-5-git-send-email-enric.balletbo@collabora.com>

Since commit e409dfbfccf9a49 ("ASoC: dapm: Add a few supply widget
sanity checks") the following error is seen:

 rockchip-snd-max98090 sound: HiFi <-> ff890000.i2s mapping ok
 rockchip-snd-max98090 sound: Connecting non-supply widget to supply widget is not supported (Headset Mic -> MICBIAS)
 rockchip-snd-max98090 sound: ASoC: no dapm match for Headset Mic --> (null) --> MICBIAS
 rockchip-snd-max98090 sound: ASoC: Failed to add route Headset Mic -> direct -> MICBIAS
 input: ROCKCHIP-I2S Headset Jack as /devices/platform/sound/sound/card0/input3

Invert the route between the Headset Mic and the bias in order to fix it.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
---
 sound/soc/rockchip/rockchip_max98090.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index abb64a5..3da7891 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -53,7 +53,7 @@ static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
 static const struct snd_soc_dapm_route rk_audio_map[] = {
 	{"IN34", NULL, "Headset Mic"},
 	{"IN34", NULL, "MICBIAS"},
-	{"MICBIAS", NULL, "Headset Mic"},
+	{"Headset Mic", NULL, "MICBIAS"},
 	{"DMICL", NULL, "Int Mic"},
 	{"Headphone", NULL, "HPL"},
 	{"Headphone", NULL, "HPR"},
-- 
2.1.0



From enric.balletbo at collabora.com  Thu May  5 01:03:36 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Thu,  5 May 2016 10:03:36 +0200
Subject: [PATCH 2/7] ASoC: rockchip: Revert "ASoC: rockchip: i2s: separate
 capture and playback"
In-Reply-To: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
References: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462435421-21205-3-git-send-email-enric.balletbo@collabora.com>

From: John Keeping <john at metanate.com>

This reverts commit eba65d179c1149cf79e68608d452631f33d7f017.

This broke audio on Veyron Jerry Chromebooks and I now cannot reproduce
the problem I was trying to fix even with this commit reverted, so it
seems that this was completely the wrong thing to do.

Reported-by: Enric Balletbo Serra <eballetbo at gmail.com>
Signed-off-by: John Keeping <john at metanate.com>
---
 sound/soc/rockchip/rockchip_i2s.c | 72 ++++++++++++++++++++++-----------------
 1 file changed, 40 insertions(+), 32 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 34743ec..574c6af 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -82,8 +82,8 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
 
 		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_TXS_START,
-				   I2S_XFER_TXS_START);
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 
 		i2s->tx_start = true;
 	} else {
@@ -92,23 +92,27 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
 
-		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_TXS_START,
-				   I2S_XFER_TXS_STOP);
-
-		regmap_update_bits(i2s->regmap, I2S_CLR,
-				   I2S_CLR_TXC,
-				   I2S_CLR_TXC);
+		if (!i2s->rx_start) {
+			regmap_update_bits(i2s->regmap, I2S_XFER,
+					   I2S_XFER_TXS_START |
+					   I2S_XFER_RXS_START,
+					   I2S_XFER_TXS_STOP |
+					   I2S_XFER_RXS_STOP);
 
-		regmap_read(i2s->regmap, I2S_CLR, &val);
+			regmap_update_bits(i2s->regmap, I2S_CLR,
+					   I2S_CLR_TXC | I2S_CLR_RXC,
+					   I2S_CLR_TXC | I2S_CLR_RXC);
 
-		/* Should wait for clear operation to finish */
-		while (val & I2S_CLR_TXC) {
 			regmap_read(i2s->regmap, I2S_CLR, &val);
-			retry--;
-			if (!retry) {
-				dev_warn(i2s->dev, "fail to clear\n");
-				break;
+
+			/* Should wait for clear operation to finish */
+			while (val) {
+				regmap_read(i2s->regmap, I2S_CLR, &val);
+				retry--;
+				if (!retry) {
+					dev_warn(i2s->dev, "fail to clear\n");
+					break;
+				}
 			}
 		}
 	}
@@ -124,8 +128,8 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
 
 		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_RXS_START,
-				   I2S_XFER_RXS_START);
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 
 		i2s->rx_start = true;
 	} else {
@@ -134,23 +138,27 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
 
-		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_RXS_START,
-				   I2S_XFER_RXS_STOP);
-
-		regmap_update_bits(i2s->regmap, I2S_CLR,
-				   I2S_CLR_RXC,
-				   I2S_CLR_RXC);
+		if (!i2s->tx_start) {
+			regmap_update_bits(i2s->regmap, I2S_XFER,
+					   I2S_XFER_TXS_START |
+					   I2S_XFER_RXS_START,
+					   I2S_XFER_TXS_STOP |
+					   I2S_XFER_RXS_STOP);
 
-		regmap_read(i2s->regmap, I2S_CLR, &val);
+			regmap_update_bits(i2s->regmap, I2S_CLR,
+					   I2S_CLR_TXC | I2S_CLR_RXC,
+					   I2S_CLR_TXC | I2S_CLR_RXC);
 
-		/* Should wait for clear operation to finish */
-		while (val & I2S_CLR_RXC) {
 			regmap_read(i2s->regmap, I2S_CLR, &val);
-			retry--;
-			if (!retry) {
-				dev_warn(i2s->dev, "fail to clear\n");
-				break;
+
+			/* Should wait for clear operation to finish */
+			while (val) {
+				regmap_read(i2s->regmap, I2S_CLR, &val);
+				retry--;
+				if (!retry) {
+					dev_warn(i2s->dev, "fail to clear\n");
+					break;
+				}
 			}
 		}
 	}
-- 
2.1.0



From enric.balletbo at collabora.com  Thu May  5 01:03:41 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Thu,  5 May 2016 10:03:41 +0200
Subject: [PATCH 7/7] ARM: dts: rockchip: veyron: Add analog audio codecs.
In-Reply-To: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
References: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462435421-21205-8-git-send-email-enric.balletbo@collabora.com>

Add analog-audio functionality for Veyron devices.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
---
 arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
index 610769d..e25bb1a 100644
--- a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
@@ -46,6 +46,7 @@
 #include <dt-bindings/clock/rockchip,rk808.h>
 #include <dt-bindings/input/input.h>
 #include "rk3288-veyron.dtsi"
+#include "rk3288-veyron-analog-audio.dtsi"
 #include "rk3288-veyron-sdmmc.dtsi"
 
 / {
-- 
2.1.0



From enric.balletbo at collabora.com  Thu May  5 01:03:39 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Thu,  5 May 2016 10:03:39 +0200
Subject: [PATCH 5/7] ASoC: rockchip-max98090: Fix DAPM unknown pin for Headset
 Jack
In-Reply-To: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
References: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462435421-21205-6-git-send-email-enric.balletbo@collabora.com>

The patch fixes the following error message.

 rockchip-snd-max98090 sound: ASoC: DAPM unknown pin Headset Jack

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
---
 sound/soc/rockchip/rockchip_max98090.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index 3da7891..40d2ec9 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -36,7 +36,7 @@
 static struct snd_soc_jack headset_jack;
 static struct snd_soc_jack_pin headset_jack_pins[] = {
 	{
-		.pin = "Headset Jack",
+		.pin = "Headphone",
 		.mask = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
 			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
 			SND_JACK_BTN_2 | SND_JACK_BTN_3,
-- 
2.1.0



From enric.balletbo at collabora.com  Thu May  5 01:03:40 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Thu,  5 May 2016 10:03:40 +0200
Subject: [PATCH 6/7] ARM: dts: rockchip: Add shared file for audio related
 nodes for veyron boards
In-Reply-To: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
References: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462435421-21205-7-git-send-email-enric.balletbo@collabora.com>

Set i2s block to "okay", add sound node for max98090 with gpios for
HP and Mic detect and pinctrl, and add a max98090 device and ts3a227e to
the correct i2c bus.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
---
 arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi | 102 ++++++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi

diff --git a/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi b/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
new file mode 100644
index 0000000..f045e1a
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
@@ -0,0 +1,102 @@
+/*
+ * Google Veyron (and derivatives) fragment for the  max98090 audio
+ * codec and analog headphone jack.
+ *
+ * Copyright 2016 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/ {
+
+	sound {
+		compatible = "rockchip,rockchip-audio-max98090";
+		rockchip,model = "ROCKCHIP-I2S";
+		rockchip,i2s-controller = <&i2s>;
+		rockchip,audio-codec = <&max98090>;
+		rockchip,hp-det-gpios = <&gpio6 5 GPIO_ACTIVE_HIGH>;
+		rockchip,mic-det-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+		rockchip,headset-codec = <&headsetcodec>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&mic_det>, <&hp_det>;
+	};
+
+	io-domains {
+		audio-supply = <&vcc18_codec>;
+	};
+};
+
+&rk808 {
+	vcc10-supply = <&vcc33_sys>;
+
+	regulators {
+		vcc18_codec: LDO_REG6 {
+			regulator-always-on;
+			regulator-boot-on;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			regulator-name = "vcc18_codec";
+			regulator-suspend-mem-disabled;
+		};
+	};
+};
+
+&i2c2 {
+	max98090: max98090 at 10 {
+		compatible = "maxim,max98090";
+		reg = <0x10>;
+		clock-names = "mclk";
+		clocks = <&cru SCLK_I2S0_OUT>;
+		interrupt-parent = <&gpio6>;
+		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&int_codec>;
+	};
+};
+
+&i2c4 {
+	headsetcodec: ts3a227e at 3b {
+		compatible = "ti,ts3a227e";
+		reg = <0x3b>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&ts3a227e_int_l>;
+		ti,micbias = <7>;		/* MICBIAS = 2.8V */
+	};
+};
+
+&i2s {
+	status = "okay";
+	clock-names = "i2s_hclk", "i2s_clk";
+	clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+};
+
+&pinctrl {
+	codec {
+		hp_det: hp-det {
+			rockchip,pins = <6 5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		/*
+		 * HACK: We're going to _pull down_ this _active low_ interrupt
+		 * so that it never fires.  We don't need this interrupt because
+		 * we've got a ts3a227e chip but the driver requires it.
+		 */
+		int_codec: int-codec {
+			rockchip,pins = <6 7 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		mic_det: mic-det {
+			rockchip,pins = <6 11 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	headset {
+		ts3a227e_int_l: ts3a227e-int-l {
+			rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+};
-- 
2.1.0



From tomeu.vizoso at collabora.com  Thu May  5 02:34:26 2016
From: tomeu.vizoso at collabora.com (Tomeu Vizoso)
Date: Thu, 5 May 2016 11:34:26 +0200
Subject: [PATCH 1/2] drm/rockchip: vop: Do check if an update is pending
 during disable
In-Reply-To: <CAAObsKCmPZBaSudVJy8BPThhoZw8VVqxicqsmc8diApajD57nA@mail.gmail.com>
References: <1459937686-9142-1-git-send-email-tomeu.vizoso@collabora.com>
 <5707043D.6060706@rock-chips.com>
 <CAAObsKAeAjUP1retiZqo5geOK2OkVjKvSB6g6nvGTh_rdNiFJQ@mail.gmail.com>
 <570AFAC2.8080907@rock-chips.com>
 <CAAObsKCmPZBaSudVJy8BPThhoZw8VVqxicqsmc8diApajD57nA@mail.gmail.com>
Message-ID: <CAAObsKBXxb8ZS3CqLy4qsDRWLvT=w2ACANCcDLE5B47nRKtvBw@mail.gmail.com>

On 20 April 2016 at 16:23, Tomeu Vizoso <tomeu.vizoso at collabora.com> wrote:
> On 11 April 2016 at 03:15, Mark yao <mark.yao at rock-chips.com> wrote:
>> On 2016?04?08? 18:54, Tomeu Vizoso wrote:
>>>
>>> On 8 April 2016 at 03:07, Mark yao <mark.yao at rock-chips.com> wrote:
>>>>
>>>> On 2016?04?06? 18:14, Tomeu Vizoso wrote:
>>>>
>>>> When a plane is being disabled but it's still enabled, do check if the
>>>> previous update has been completed by reading yrgb_mst back.
>>>>
>>>> Otherwise, pending pageflips would remain pending after a CRTC is
>>>> disabled.
>>>>
>>>> Signed-off-by: Tomeu Vizoso <tomeu.vizoso at collabora.com>
>>>> ---
>>>>   drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 +++--
>>>>   1 file changed, 3 insertions(+), 2 deletions(-)
>>>>
>>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>> b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>> index a9b1e8b5ac85..f46b1fd1887b 100644
>>>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>> @@ -1064,8 +1064,9 @@ static bool vop_win_pending_is_complete(struct
>>>> vop_win
>>>> *vop_win)
>>>>    struct vop_plane_state *state = to_vop_plane_state(plane->state);
>>>>    dma_addr_t yrgb_mst;
>>>>
>>>> - if (!state->enable)
>>>> - return VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0;
>>>> + if (!state->enable &&
>>>> +    VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0)
>>>> + return true;
>>>>
>>>>
>>>> It is wrong, the patch would cause a bug.
>>>>
>>>> when state->enable is 0, check yrgb_mst == state->yrgb_mst always be
>>>> true,
>>>> because state->yrgb_mst not update on plane disabled funtion, that would
>>>> cause iommu crash.
>>>
>>> Sorry, but I don't understand where's the bug and what could cause
>>> that crash. What the existing code was doing is saying that a pageflip
>>> event is still pending if we have told the plane to disable but for
>>> some reason it hasn't yet.
>>>
>>> With this modification, if we read back that it's already disabled, we
>>> return true as before. But if we read back that it isn't disabled yet,
>>> then we still check the fb pointers and compare them.
>>>
>>> The iommu mapping is removed when the _CRTC_ is disabled, and what
>>> this series does is to wait for the pending pageflip to finish before
>>> conitnuing with CRTC disablement.
>>
>>
>> the iommu mapping will unmap after plane disabled, we need sure that the
>> plane really disabled before unmap, if not, the unmap may call before plane
>> really disable, vop may access unmap address, then would get iommu page
>> fault.
>
> Sorry, but I still don't see the error condition that you are
> describing. AFAICS, the unmap will happen after the last pageflip has
> completed.
>
>>>> About pending pageflips would remain pending, can you  describe more info
>>>> about it? I think those pending pageflips should be ignore when CRTC is
>>>> disabled.
>>>
>>> Well, right now in rockchip-drm pending pageflips won't be ignored
>>> when a CRTC is disabled, but will be delivered when it's re-enabled.
>>>
>>> If they would be to be ignored (understanding that as dropped), that
>>> would require modifications to clients so they keep track of which fbs
>>> were used in a particular crtc and destroy them when the crtc is
>>> disabled, but that would be incorrect when using the i915 DRM driver
>>> (I also assume others do the same). Given that the pageflip ioctl
>>> isn't driver-specific, I think there cannot be such a difference in
>>> behavior between drivers.
>>>
>>> With the current behavior (pending pageflip events being delayed until
>>> the CRTC is enabled again), compositors and other clients will be
>>> holding on to the fb in the pending pageflip until an arbitrary point
>>> in the future that may not ever come. To me that sounds like a serious
>>> modification of the assumptions on fb lifecycle that might not be
>>> warranted.
>>>
>>> So in summary, even if I haven't found any explicit documentation on
>>> this, I think the ABI is that any pending pageflips are to be
>>> delivered when that CRTC is being disabled and not later.
>>
>>
>> on drivers/gpu/drm/rockchip/rockchip_drm_fb.c
>>
>> drm_atomic_helper_commit_planes(dev, state, true);
>> rockchip_atomic_wait_for_complete(dev, state);
>>
>> We set active_only = true, I think planes can only update when crtc is
>> active. and rockchip_atomic_wait_for_complete only wait when crtc is active.
>
> That's fine, but if a pageflip is pending when the client requests the
> CRTC to be disabled, we need to wait for the event to be emitted
> before we actually disable the HW.

Hi Mark,

could you tell me if you agree that there's a bug that needs to be
solved, and if so, what do you think we should do about it?

Thanks,

Tomeu

> Regards,
>
> Tomeu
>
>> Thanks.
>>
>>> Thanks,
>>>
>>> Tomeu
>>>
>>>> Thanks.
>>>>
>>>>
>>>>    yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win->data);
>>>>
>>>>
>>>>
>>>> --
>>>> ?ark Yao
>>>>
>>>>
>>>> _______________________________________________
>>>> dri-devel mailing list
>>>> dri-devel at lists.freedesktop.org
>>>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>
>>>
>>>
>>
>>
>> --
>> ?ark Yao
>>
>>
>> _______________________________________________
>> dri-devel mailing list
>> dri-devel at lists.freedesktop.org
>> https://lists.freedesktop.org/mailman/listinfo/dri-devel


From tomeu.vizoso at collabora.com  Thu May  5 06:30:32 2016
From: tomeu.vizoso at collabora.com (Tomeu Vizoso)
Date: Thu, 5 May 2016 15:30:32 +0200
Subject: [RFC PATCH 0/3] clk: attempt to keep requested rate on parent
 changes
In-Reply-To: <1462206982-10444-1-git-send-email-heiko@sntech.de>
References: <1462206982-10444-1-git-send-email-heiko@sntech.de>
Message-ID: <572B4AF8.6070509@collabora.com>

On 05/02/2016 06:36 PM, Heiko Stuebner wrote:
> I remember reading about people discussing that problem in the past, but
> haven't been able to find another approach to it yet [or I'm just blind
> as happens to often].
> 
> Our problem is the following clock structure:
> 
> [anotherPLL]
>     |
>     ------ [div] ----- dclk_vop
>     |
> [   vpll   ] --------- hdmi_phy
> 
> 
> We need to set the vpll dynamically but still want to retain

Guess something is missing here?

> The other option that comes to mind, would be to have a clock-notifier,
> in the drm driver, but calling clk_set_rate from their looks like it
> shouldn't work due to the prepare mutex already being held.
> 
> 
> The whole thing is labeled RFC because while it works for us and solves
> the problem, I'm not sure if I'm overlooking some important aspect or
> am interferring with some other planned approach for that issue.

I like this approach very much and wonder in what cases it wouldn't be
desirable to re-try to achieve the requested rate after a change in an
ancestor clock.

Besides that, do you know already if it would solve the conflicts
described by Doug in the thread below?

http://thread.gmane.org/gmane.linux.kernel/1820653/focus=3298

Thanks,

Tomeu




> Heiko Stuebner (3):
>   clk: fix inconsistent use of req_rate
>   clk: adjust clocks to their requested rate after parent changes
>   clk: rockchip: make rk3399 vop dclks keep their rate on parent rate changes
> 
>  drivers/clk/clk.c                 | 37 +++++++++++++++++++++++++++++--------
>  drivers/clk/rockchip/clk-rk3399.c |  4 ++--
>  include/linux/clk-provider.h      |  1 +
>  3 files changed, 32 insertions(+), 10 deletions(-)
> 



From heiko at sntech.de  Thu May  5 08:07:41 2016
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Thu, 05 May 2016 17:07:41 +0200
Subject: [RFC PATCH 0/3] clk: attempt to keep requested rate on parent
 changes
In-Reply-To: <572B4AF8.6070509@collabora.com>
References: <1462206982-10444-1-git-send-email-heiko@sntech.de>
 <572B4AF8.6070509@collabora.com>
Message-ID: <4828628.D4nfByUg7D@diego>

Hi Tomeu,

Am Donnerstag, 5. Mai 2016, 15:30:32 schrieb Tomeu Vizoso:
> On 05/02/2016 06:36 PM, Heiko Stuebner wrote:
> > I remember reading about people discussing that problem in the past, but
> > haven't been able to find another approach to it yet [or I'm just blind
> > as happens to often].
> > 
> > Our problem is the following clock structure:
> > 
> > [anotherPLL]
> > 
> >     ------ [div] ----- dclk_vop
> > 
> > [   vpll   ] --------- hdmi_phy
> > 
> > 
> > We need to set the vpll dynamically but still want to retain
> 
> Guess something is missing here?

looks like I forgot to finish my thought "... the vpll as regular dclk_vop 
source".


> > The other option that comes to mind, would be to have a clock-notifier,
> > in the drm driver, but calling clk_set_rate from their looks like it
> > shouldn't work due to the prepare mutex already being held.
> > 
> > 
> > The whole thing is labeled RFC because while it works for us and solves
> > the problem, I'm not sure if I'm overlooking some important aspect or
> > am interferring with some other planned approach for that issue.
> 
> I like this approach very much and wonder in what cases it wouldn't be
> desirable to re-try to achieve the requested rate after a change in an
> ancestor clock.

I guess that is mainly me being overly careful and not overlooking if the 
clock-framework can get into any troubled state if all clocks do this, but I 
guess it should just work ;-) .


> Besides that, do you know already if it would solve the conflicts
> described by Doug in the thread below?
> 
> http://thread.gmane.org/gmane.linux.kernel/1820653/focus=3298

I think the big issue on the rk3288 is, who is actually in charge of 
controlling the npll frequency.

On the rk3399 the vpll is supplied unmodified to the hdmiphy, while as a 
dclk_vop source it goes through a divider first. So it's pretty clear that the 
hdmiphy will control the core frequency while other users need to adapt to 
what they get.

On the rk3288 the npll is a possible source to both the hdmi- as well as the 
edp-clock (and some others as well), so when it gets adapted dynamically, wo 
is going to be in charge and who needs to adapt ... and how do we set this 
hierarchy.


Heiko


From broonie at kernel.org  Thu May  5 08:56:23 2016
From: broonie at kernel.org (Mark Brown)
Date: Thu, 05 May 2016 16:56:23 +0100
Subject: Applied "ASoC: rockchip: Revert "ASoC: rockchip: i2s: remove unused
 variables"" to the asoc tree
In-Reply-To: <1462373686-21794-1-git-send-email-john@metanate.com>
Message-ID: <E1ayLdX-0004kH-IJ@debutante>

The patch

   ASoC: rockchip: Revert "ASoC: rockchip: i2s: remove unused variables"

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From a6e806c49e3265494ac6fe6ec88ed5c010652e0d Mon Sep 17 00:00:00 2001
From: John Keeping <john at metanate.com>
Date: Wed, 4 May 2016 17:21:56 +0100
Subject: [PATCH] ASoC: rockchip: Revert "ASoC: rockchip: i2s: remove unused
 variables"

This reverts commit 5938448b99275cba95167c3f9d39ca9225fdad38.

It turns out that the commit that made these variables unused is wrong
so we're about to revert it.  Bring back the variables in prepration.

Signed-off-by: John Keeping <john at metanate.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/rockchip/rockchip_i2s.c | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 2f8e20416bd3..34743ec61c49 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -34,6 +34,13 @@ struct rk_i2s_dev {
 
 	struct regmap *regmap;
 
+/*
+ * Used to indicate the tx/rx status.
+ * I2S controller hopes to start the tx and rx together,
+ * also to stop them when they are both try to stop.
+*/
+	bool tx_start;
+	bool rx_start;
 	bool is_master_mode;
 };
 
@@ -77,7 +84,11 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_XFER,
 				   I2S_XFER_TXS_START,
 				   I2S_XFER_TXS_START);
+
+		i2s->tx_start = true;
 	} else {
+		i2s->tx_start = false;
+
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
 
@@ -115,7 +126,11 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_XFER,
 				   I2S_XFER_RXS_START,
 				   I2S_XFER_RXS_START);
+
+		i2s->rx_start = true;
 	} else {
+		i2s->rx_start = false;
+
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
 
-- 
2.8.1



From broonie at kernel.org  Thu May  5 08:56:20 2016
From: broonie at kernel.org (Mark Brown)
Date: Thu, 05 May 2016 16:56:20 +0100
Subject: Applied "ASoC: rockchip: Revert "ASoC: rockchip: i2s: separate
 capture and playback"" to the asoc tree
In-Reply-To: <1462373686-21794-2-git-send-email-john@metanate.com>
Message-ID: <E1ayLdU-0004jH-K0@debutante>

The patch

   ASoC: rockchip: Revert "ASoC: rockchip: i2s: separate capture and playback"

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 7e885d211f023dfd201fad8246bbf3c3bd126c61 Mon Sep 17 00:00:00 2001
From: John Keeping <john at metanate.com>
Date: Wed, 4 May 2016 17:21:57 +0100
Subject: [PATCH] ASoC: rockchip: Revert "ASoC: rockchip: i2s: separate capture
 and playback"

This reverts commit eba65d179c1149cf79e68608d452631f33d7f017.

This broke audio on Veyron Jerry Chromebooks and I now cannot reproduce
the problem I was trying to fix even with this commit reverted, so it
seems that this was completely the wrong thing to do.

Reported-by: Enric Balletbo Serra <eballetbo at gmail.com>
Signed-off-by: John Keeping <john at metanate.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/rockchip/rockchip_i2s.c | 72 ++++++++++++++++++++++-----------------
 1 file changed, 40 insertions(+), 32 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 34743ec61c49..574c6af28c06 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -82,8 +82,8 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_ENABLE);
 
 		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_TXS_START,
-				   I2S_XFER_TXS_START);
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 
 		i2s->tx_start = true;
 	} else {
@@ -92,23 +92,27 @@ static void rockchip_snd_txctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_TDE_ENABLE, I2S_DMACR_TDE_DISABLE);
 
-		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_TXS_START,
-				   I2S_XFER_TXS_STOP);
-
-		regmap_update_bits(i2s->regmap, I2S_CLR,
-				   I2S_CLR_TXC,
-				   I2S_CLR_TXC);
+		if (!i2s->rx_start) {
+			regmap_update_bits(i2s->regmap, I2S_XFER,
+					   I2S_XFER_TXS_START |
+					   I2S_XFER_RXS_START,
+					   I2S_XFER_TXS_STOP |
+					   I2S_XFER_RXS_STOP);
 
-		regmap_read(i2s->regmap, I2S_CLR, &val);
+			regmap_update_bits(i2s->regmap, I2S_CLR,
+					   I2S_CLR_TXC | I2S_CLR_RXC,
+					   I2S_CLR_TXC | I2S_CLR_RXC);
 
-		/* Should wait for clear operation to finish */
-		while (val & I2S_CLR_TXC) {
 			regmap_read(i2s->regmap, I2S_CLR, &val);
-			retry--;
-			if (!retry) {
-				dev_warn(i2s->dev, "fail to clear\n");
-				break;
+
+			/* Should wait for clear operation to finish */
+			while (val) {
+				regmap_read(i2s->regmap, I2S_CLR, &val);
+				retry--;
+				if (!retry) {
+					dev_warn(i2s->dev, "fail to clear\n");
+					break;
+				}
 			}
 		}
 	}
@@ -124,8 +128,8 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_ENABLE);
 
 		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_RXS_START,
-				   I2S_XFER_RXS_START);
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START,
+				   I2S_XFER_TXS_START | I2S_XFER_RXS_START);
 
 		i2s->rx_start = true;
 	} else {
@@ -134,23 +138,27 @@ static void rockchip_snd_rxctrl(struct rk_i2s_dev *i2s, int on)
 		regmap_update_bits(i2s->regmap, I2S_DMACR,
 				   I2S_DMACR_RDE_ENABLE, I2S_DMACR_RDE_DISABLE);
 
-		regmap_update_bits(i2s->regmap, I2S_XFER,
-				   I2S_XFER_RXS_START,
-				   I2S_XFER_RXS_STOP);
-
-		regmap_update_bits(i2s->regmap, I2S_CLR,
-				   I2S_CLR_RXC,
-				   I2S_CLR_RXC);
+		if (!i2s->tx_start) {
+			regmap_update_bits(i2s->regmap, I2S_XFER,
+					   I2S_XFER_TXS_START |
+					   I2S_XFER_RXS_START,
+					   I2S_XFER_TXS_STOP |
+					   I2S_XFER_RXS_STOP);
 
-		regmap_read(i2s->regmap, I2S_CLR, &val);
+			regmap_update_bits(i2s->regmap, I2S_CLR,
+					   I2S_CLR_TXC | I2S_CLR_RXC,
+					   I2S_CLR_TXC | I2S_CLR_RXC);
 
-		/* Should wait for clear operation to finish */
-		while (val & I2S_CLR_RXC) {
 			regmap_read(i2s->regmap, I2S_CLR, &val);
-			retry--;
-			if (!retry) {
-				dev_warn(i2s->dev, "fail to clear\n");
-				break;
+
+			/* Should wait for clear operation to finish */
+			while (val) {
+				regmap_read(i2s->regmap, I2S_CLR, &val);
+				retry--;
+				if (!retry) {
+					dev_warn(i2s->dev, "fail to clear\n");
+					break;
+				}
 			}
 		}
 	}
-- 
2.8.1



From briannorris at chromium.org  Thu May  5 09:37:48 2016
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 5 May 2016 09:37:48 -0700
Subject: [PATCH] clk: rockchip: fix the rk3399 sdmmc sample / drv name
In-Reply-To: <1462404985-27957-1-git-send-email-dianders@chromium.org>
References: <1462404985-27957-1-git-send-email-dianders@chromium.org>
Message-ID: <20160505163748.GA97052@google.com>

On Wed, May 04, 2016 at 04:36:25PM -0700, Douglas Anderson wrote:
> The rk3399 clock table had a simple typo in it, calling the SDMMC sample
> and drive clocks by the wrong name.  Fix this minor typo.
> 
> Signed-off-by: Douglas Anderson <dianders at chromium.org>

LGTM.

Tested-by: Brian Norris <briannorris at chromium.org>
Acked-by: Brian Norris <briannorris at chromium.org>

> ---
>  drivers/clk/rockchip/clk-rk3399.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
> index 5248726af86d..291543f52caa 100644
> --- a/drivers/clk/rockchip/clk-rk3399.c
> +++ b/drivers/clk/rockchip/clk-rk3399.c
> @@ -894,8 +894,8 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
>  			RK3399_CLKSEL_CON(16), 8, 3, MFLAGS, 0, 7, DFLAGS,
>  			RK3399_CLKGATE_CON(6), 1, GFLAGS),
>  
> -	MMC(SCLK_SDMMC_DRV,     "emmc_drv",    "clk_sdmmc", RK3399_SDMMC_CON0, 1),
> -	MMC(SCLK_SDMMC_SAMPLE,  "emmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1),
> +	MMC(SCLK_SDMMC_DRV,     "sdmmc_drv",    "clk_sdmmc", RK3399_SDMMC_CON0, 1),
> +	MMC(SCLK_SDMMC_SAMPLE,  "sdmmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1),
>  
>  	MMC(SCLK_SDIO_DRV,      "sdio_drv",    "clk_sdio",  RK3399_SDIO_CON0,  1),
>  	MMC(SCLK_SDIO_SAMPLE,   "sdio_sample", "clk_sdio",  RK3399_SDIO_CON1,  1),
> -- 
> 2.8.0.rc3.226.g39d4020


From briannorris at chromium.org  Thu May  5 10:07:52 2016
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 5 May 2016 10:07:52 -0700
Subject: usb: dwc3: host: inherit dma configuration from parent dev
In-Reply-To: <1461612094-30939-1-git-send-email-grygorii.strashko@ti.com>
References: <1461612094-30939-1-git-send-email-grygorii.strashko@ti.com>
Message-ID: <20160505170752.GA118697@google.com>

On Mon, Apr 25, 2016 at 10:21:34PM +0300, Strashko, Grygorii wrote:
> Now not all DMA paremters configured properly for "xhci-hcd" platform
> device which is created manually. For example: dma_pfn_offset, dam_ops
> and iommu configuration will not corresponds "dwc3" devices
> configuration. As result, this will cause problems like wrong DMA
> addresses translation on platforms with LPAE enabled like Keystone 2.
> 
> When platform is using DT boot mode the DMA configuration will be
> parsed and applied from DT, so, to fix this issue, reuse
> of_dma_configure() API and retrieve DMA configuartion for "xhci-hcd"
> from DWC3 device node.
> 
> Cc: David Fisher <david.fisher1 at synopsys.com>
> Cc: Catalin Marinas <catalin.marinas at arm.com>
> Cc: "Thang Q. Nguyen" <tqnguyen at apm.com>
> Cc: Yoshihiro Shimoda <yoshihiro.shimoda.uh at renesas.com>
> Signed-off-by: Grygorii Strashko <grygorii.strashko at ti.com>

Tested-by: Brian Norris <briannorris at chromium.org>

What's the status of this? I see that there was some divergent
discussion about the merits of a dma_inherit() API...

FWIW, I'll reiterate Grygorii's note that Felipe's alternative patch
does NOT resolve the problem with the creation of the xhci-hcd platform
device:

https://patchwork.kernel.org/patch/8952721/

Brian

> ---
> drivers/usb/dwc3/host.c | 15 ++++++++++-----
>  1 file changed, 10 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/usb/dwc3/host.c b/drivers/usb/dwc3/host.c
> index c679f63..93c8ef9 100644
> --- a/drivers/usb/dwc3/host.c
> +++ b/drivers/usb/dwc3/host.c
> @@ -17,6 +17,7 @@
>  
>  #include <linux/platform_device.h>
>  #include <linux/usb/xhci_pdriver.h>
> +#include <linux/of_device.h>
>  
>  #include "core.h"
>  
> @@ -32,12 +33,7 @@ int dwc3_host_init(struct dwc3 *dwc)
>  		return -ENOMEM;
>  	}
>  
> -	dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
> -
>  	xhci->dev.parent	= dwc->dev;
> -	xhci->dev.dma_mask	= dwc->dev->dma_mask;
> -	xhci->dev.dma_parms	= dwc->dev->dma_parms;
> -
>  	dwc->xhci = xhci;
>  
>  	ret = platform_device_add_resources(xhci, dwc->xhci_resources,
> @@ -62,6 +58,15 @@ int dwc3_host_init(struct dwc3 *dwc)
>  	phy_create_lookup(dwc->usb3_generic_phy, "usb3-phy",
>  			  dev_name(&xhci->dev));
>  
> +	if (IS_ENABLED(CONFIG_OF) && dwc->dev->of_node) {
> +		of_dma_configure(&xhci->dev, dwc->dev->of_node);
> +	} else {
> +		dma_set_coherent_mask(&xhci->dev, dwc->dev->coherent_dma_mask);
> +
> +		xhci->dev.dma_mask	= dwc->dev->dma_mask;
> +		xhci->dev.dma_parms	= dwc->dev->dma_parms;
> +	}
> +
>  	ret = platform_device_add(xhci);
>  	if (ret) {
>  		dev_err(dwc->dev, "failed to register xHCI device\n");


From broonie at kernel.org  Thu May  5 12:18:44 2016
From: broonie at kernel.org (Mark Brown)
Date: Thu, 5 May 2016 20:18:44 +0100
Subject: [PATCH 4/7] ASoC: rockchip-max98090: Fix the Headset Mic route.
In-Reply-To: <1462435421-21205-5-git-send-email-enric.balletbo@collabora.com>
References: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
 <1462435421-21205-5-git-send-email-enric.balletbo@collabora.com>
Message-ID: <20160505191844.GL6292@sirena.org.uk>

On Thu, May 05, 2016 at 10:03:38AM +0200, Enric Balletbo i Serra wrote:
> Since commit e409dfbfccf9a49 ("ASoC: dapm: Add a few supply widget
> sanity checks") the following error is seen:


>  rockchip-snd-max98090 sound: Connecting non-supply widget to supply widget is not supported (Headset Mic -> MICBIAS)
>  rockchip-snd-max98090 sound: ASoC: no dapm match for Headset Mic --> (null) --> MICBIAS
>  rockchip-snd-max98090 sound: ASoC: Failed to add route Headset Mic -> direct -> MICBIAS
>  input: ROCKCHIP-I2S Headset Jack as /devices/platform/sound/sound/card0/input3

> Invert the route between the Headset Mic and the bias in order to fix it.

This isn't just noise, this is telling you that the route has always
been broken...
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160505/56a33cd0/attachment.sig>

From broonie at kernel.org  Thu May  5 12:20:10 2016
From: broonie at kernel.org (Mark Brown)
Date: Thu, 5 May 2016 20:20:10 +0100
Subject: [PATCH 5/7] ASoC: rockchip-max98090: Fix DAPM unknown pin for
 Headset Jack
In-Reply-To: <1462435421-21205-6-git-send-email-enric.balletbo@collabora.com>
References: <1462435421-21205-1-git-send-email-enric.balletbo@collabora.com>
 <1462435421-21205-6-git-send-email-enric.balletbo@collabora.com>
Message-ID: <20160505192010.GM6292@sirena.org.uk>

On Thu, May 05, 2016 at 10:03:39AM +0200, Enric Balletbo i Serra wrote:
> The patch fixes the following error message.
> 
>  rockchip-snd-max98090 sound: ASoC: DAPM unknown pin Headset Jack

>  	{
> -		.pin = "Headset Jack",
> +		.pin = "Headphone",

...and makes automatic DAPM management of the headphone jack work.
Again, it's not just shutting up warnings it's fixing an actual bug.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160505/c28ec0e9/attachment.sig>

From heiko at sntech.de  Thu May  5 14:36:49 2016
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Thu, 05 May 2016 23:36:49 +0200
Subject: [PATCH v7 5/9] i2c: rk3x: Change SoC data to not use array
In-Reply-To: <1462372418-6349-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372418-6349-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <2061861.OMNZ1I2HYA@diego>

Am Mittwoch, 4. Mai 2016, 22:33:38 schrieb David Wu:
> Signed-off-by: David Wu <david.wu at rock-chips.com>

that makes the code look nicer (and of course prepares for you further 
changes), so

Reviewed-by: Heiko Stuebner <heiko at sntech.de>

> ---
>  drivers/i2c/busses/i2c-rk3x.c | 38 ++++++++++++++++++++++++++++++--------
>  1 file changed, 30 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
> index 0838fcf..9686c81 100644
> --- a/drivers/i2c/busses/i2c-rk3x.c
> +++ b/drivers/i2c/busses/i2c-rk3x.c
> @@ -867,17 +867,39 @@ static const struct i2c_algorithm rk3x_i2c_algorithm =
> { .functionality		= rk3x_i2c_func,
>  };
> 
> -static struct rk3x_i2c_soc_data soc_data[3] = {
> -	{ .grf_offset = 0x154 }, /* rk3066 */
> -	{ .grf_offset = 0x0a4 }, /* rk3188 */
> -	{ .grf_offset = -1 },    /* no I2C switching needed */
> +static const struct rk3x_i2c_soc_data rk3066_soc_data = {
> +	.grf_offset = 0x154,
> +};
> +
> +static const struct rk3x_i2c_soc_data rk3188_soc_data = {
> +	.grf_offset = 0x0a4,
> +};
> +
> +static const struct rk3x_i2c_soc_data rk3228_soc_data = {
> +	.grf_offset = -1,
> +};
> +
> +static const struct rk3x_i2c_soc_data rk3288_soc_data = {
> +	.grf_offset = -1,
>  };
> 
>  static const struct of_device_id rk3x_i2c_match[] = {
> -	{ .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] },
> -	{ .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] },
> -	{ .compatible = "rockchip,rk3228-i2c", .data = (void *)&soc_data[2] },
> -	{ .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] },
> +	{
> +		.compatible = "rockchip,rk3066-i2c",
> +		.data = (void *)&rk3066_soc_data
> +	},
> +	{
> +		.compatible = "rockchip,rk3188-i2c",
> +		.data = (void *)&rk3188_soc_data
> +	},
> +	{
> +		.compatible = "rockchip,rk3228-i2c",
> +		.data = (void *)&rk3228_soc_data
> +	},
> +	{
> +		.compatible = "rockchip,rk3288-i2c",
> +		.data = (void *)&rk3288_soc_data
> +	},
>  	{},
>  };
>  MODULE_DEVICE_TABLE(of, rk3x_i2c_match);



From robh at kernel.org  Thu May  5 15:12:12 2016
From: robh at kernel.org (Rob Herring)
Date: Thu, 5 May 2016 17:12:12 -0500
Subject: [PATCH v7 7/9] dt-bindings: i2c: rk3x: add support for rk3399
In-Reply-To: <1462372523-6444-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372523-6444-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <20160505221212.GA26820@rob-hp-laptop>

On Wed, May 04, 2016 at 10:35:23PM +0800, David Wu wrote:
> The bus clock and function clock are separated at rk3399,
> and others use one clock as the bus clock and function clock.
> 
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> ---
>  Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 16 +++++++++++++---
>  1 file changed, 13 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> index 0b4a85f..82b6f6b 100644
> --- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> +++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> @@ -6,10 +6,20 @@ RK3xxx SoCs.
>  Required properties :
>  
>   - reg : Offset and length of the register set for the device
> - - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c",
> -		"rockchip,rk3228-i2c" or "rockchip,rk3288-i2c".
> + - compatible: should be one of the followings

s/followings/following:/

> +   - "rockchip,rk3066-i2c": for rk3066
> +   - "rockchip,rk3188-i2c": for rk3188
> +   - "rockchip,rk3228-i2c": for rk3228
> +   - "rockchip,rk3288-i2c": for rk3288
> +   - "rockchip,rk3399-i2c": for rk3399
>   - interrupts : interrupt number
> - - clocks : parent clock
> + - clocks: See ../clock/clock-bindings.txt
> +   - For older hardware (rk3066, rk3188, rk3228, rk3288):
> +     - There is one clock that's used both to derive the functional clock
> +       for the device and as the bus clock.  REQUIRED.

This is the required section, so REQUIRED is redundant.

> +   - For newer hardware (rk3399): specify by name
> +     - "i2c": REQUIRED. This is used to derive the functional clock.
> +     - "pclk": REQUIRED. This is the bus clock.equired on RK3066, RK3188 :

This doesn't make sense. The first line says this applies to rk3399, but 
then here it is talking about other parts.

And there's a typo.

>  
>  Required on RK3066, RK3188 :
>  
> -- 
> 1.9.1
> 
> 


From dianders at chromium.org  Thu May  5 15:55:19 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 5 May 2016 15:55:19 -0700
Subject: [PATCH v7 2/9] i2c: rk3x: use struct "rk3x_i2c_calced_timings"
In-Reply-To: <1462371194-5809-3-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462371194-5809-3-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=WAbedAB78shifxwjmZ-od8rhOiNz80rpdqfwzRsdX6WQ@mail.gmail.com>

David,

On Wed, May 4, 2016 at 7:13 AM, David Wu <david.wu at rock-chips.com> wrote:
> Signed-off-by: David Wu <david.wu at rock-chips.com>

Usually folks like a description and not just a subject line.  I'd add
a description like:

The "div_high" and "div_low" values are always used together.  Group them
into a structure to make it easier to pass them both around.  This
structure also provides a place for future calculated timings.

> ---
> Change in v7:
> - none
>
>  drivers/i2c/busses/i2c-rk3x.c | 55 +++++++++++++++++++++++++------------------
>  1 file changed, 32 insertions(+), 23 deletions(-)

Other than the description, I think this looks fine.

IMHO this can be applied any time independent of any earlier patches.

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Thu May  5 15:55:54 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 5 May 2016 15:55:54 -0700
Subject: [PATCH v7 3/9] i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
In-Reply-To: <1462371194-5809-4-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462371194-5809-4-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=XpS4UYR5ORXUOGJXPXBr_Tpc6r87+Tm83KE654ZbkdzA@mail.gmail.com>

David,

On Wed, May 4, 2016 at 7:13 AM, David Wu <david.wu at rock-chips.com> wrote:
> Call rk3x_i2c_setup() before rk3x_i2c_start()
> and the last thing in setup was to clean the IPD,
> so no reason to do it at the beginning of start.
>
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> ---
> Change in v7:
> - none
>
>  drivers/i2c/busses/i2c-rk3x.c | 1 -
>  1 file changed, 1 deletion(-)

Looks great.  Thanks for splitting this out from other patches--makes
it much more obvious what's happening!  :)

IMHO this can be applied any time independent of any earlier patches.

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Thu May  5 15:56:45 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 5 May 2016 15:56:45 -0700
Subject: [PATCH v7 4/9] i2c: rk3x: Move setting STATE_START and add
 STATE_SETUP
In-Reply-To: <1462371194-5809-5-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462371194-5809-5-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=WVKpJJbqc=UYbeObDurjte0iQOzvLL++i=wM9=TBeCDQ@mail.gmail.com>

David,

On Wed, May 4, 2016 at 7:13 AM, David Wu <david.wu at rock-chips.com> wrote:
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> ---
> Change in v7:
> - none
>
>  drivers/i2c/busses/i2c-rk3x.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)

Probably this change could be dropped now.  Switching the location of
setting START_START was much more important when you were supporting
HIGH SPEED mode.  I don't think we need it anymore, right?

...if we want to keep this change, I'd say:

1. Add a description, like maybe:

To help with debugging add a STATE_SETUP between STATE_IDLE and
STATE_START to make it more obvious that we're not actually idle but we
also haven't initiated the start bit.  This change is not expected to
have any impact but it does delay the changing of state to STATE_START.
If previously we were getting an erroneous interrupt before we actually
sent the start bit we'll now be treating that differently.  The new
behavior (catching the erroneous interrupt) should be better.

2. Change "i2c->state = STATE_SETUP" to the _start_ of
rk3x_i2c_setup().  That would have a better chance of catching a
spurious interrupt.

3. Add an error check at the start of rk3x_i2c_irq() similar to the
check for STATE_IDLE (or use the same check and modify the printk).
Specifically the justification for adding STATE_SETUP is to help with
debugging (catch interrupts that were unexpected and print more info
about our state), so we should make it useful for this.


-Doug


From dianders at chromium.org  Thu May  5 15:57:39 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 5 May 2016 15:57:39 -0700
Subject: [PATCH v7 5/9] i2c: rk3x: Change SoC data to not use array
In-Reply-To: <1462372418-6349-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372418-6349-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=UsLmiASrso1SM5aGQPmJKNSXS260E7fiiYgmFQ4t1jpA@mail.gmail.com>

Hi,

On Wed, May 4, 2016 at 7:33 AM, David Wu <david.wu at rock-chips.com> wrote:
> Signed-off-by: David Wu <david.wu at rock-chips.com>

nit: $SUBJECT should probably mention that this also constifies the SoC data.


Again, needs description, like maybe:

Specifying the i2c SoC data in an array provides very little benefit and
gets unwieldly / confusing as the array grows since the next bit of code
needs to refer to elements in the array by their raw integral index.

Let's just create a single 'static const' structure for each SoC so that
we can refer to these structures by ID.


IMHO this can be applied any time independent of any earlier patches.

Suggested-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Thu May  5 15:58:47 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 5 May 2016 15:58:47 -0700
Subject: [PATCH v7 6/9] i2c: rk3x: Move spec timing data to "static const"
 structs
In-Reply-To: <1462372472-6396-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372472-6396-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=Vg+umhA73uR66AdFmaNKhpyXCYojqE9kZJqkTOsyK_Jg@mail.gmail.com>

David,

On Wed, May 4, 2016 at 7:34 AM, David Wu <david.wu at rock-chips.com> wrote:
> Signed-off-by: David Wu <david.wu at rock-chips.com>

As you can probably guess, again a description would be nice.  Like maybe:

The i2c timing specs are really just constant data.  There's no reason
to write code to init them, so move them out to structures.  This not
only is a cleaner solution but it will reduce code duplication when we
introduce a new variant of rk3x_i2c_calc_divs() in a future patch.

That helps someone reading the patch understand the motivation.


> @@ -76,6 +76,51 @@ enum {
>  #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
>
>  /**
> + * struct i2c_spec_values:
> + * @min_hold_start_ns: min hold time (repeated) START condition
> + * @min_low_ns: min LOW period of the SCL clock
> + * @min_high_ns: min HIGH period of the SCL cloc
> + * @min_setup_start_ns: min set-up time for a repeated START conditio
> + * @max_data_hold_ns: max data hold time
> + * @min_data_setup_ns: min data set-up time
> + * @min_setup_stop_ns: min set-up time for STOP condition
> + * @min_hold_buffer_ns: min bus free time between a STOP and
> + * START condition
> + */
> +struct i2c_spec_values {
> +       unsigned long min_hold_start_ns;
> +       unsigned long min_low_ns;
> +       unsigned long min_high_ns;
> +       unsigned long min_setup_start_ns;
> +       unsigned long max_data_hold_ns;
> +       unsigned long min_data_setup_ns;
> +       unsigned long min_setup_stop_ns;
> +       unsigned long min_hold_buffer_ns;
> +};
> +
> +static const struct i2c_spec_values standard_mode_spec = {
> +       .min_hold_start_ns = 4000,
> +       .min_low_ns = 4700,
> +       .min_high_ns = 4000,
> +       .min_setup_start_ns = 4700,
> +       .max_data_hold_ns = 3450,
> +       .min_data_setup_ns = 250,
> +       .min_setup_stop_ns = 4000,
> +       .min_hold_buffer_ns = 4700,

There are more spec values than are currently used in this patch.
Personally I'm OK with that, but if you wanted to be totally clean
this patch would only include the spec values that were needed, then
introduce the additional values in the rk3399 patch.


> @@ -492,6 +548,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
>         unsigned long min_div_for_hold, min_total_div;
>         unsigned long extra_div, extra_low_div, ideal_low_div;
>
> +       unsigned long data_hold_buffer_ns = 50;

aside (feel free to ignore): Gosh, I kinda forgot what the heck this
value was for.  I guess it's not anything in the spec.  I have a
feeling it was some sort of slop value that someone felt was
necessary, but I don't quite remember.  Oh well, I guess we leave it
there since I'd rather not mess with timings on old hardware that are
apparently working for everyone.  :-P


In any case, aside from the missing description:

Suggested-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Douglas Anderson <dianders at chromium.org>

IMHO this can be applied any time independent of any earlier patches.


-Doug


From dianders at chromium.org  Thu May  5 15:59:58 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 5 May 2016 15:59:58 -0700
Subject: [PATCH v7 7/9] dt-bindings: i2c: rk3x: add support for rk3399
In-Reply-To: <1462372523-6444-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372523-6444-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=XXojzZiVFuXuChZdDeTxE6tFSJZ=8FqLpVTG2L6xWpBg@mail.gmail.com>

Hi,

On Wed, May 4, 2016 at 7:35 AM, David Wu <david.wu at rock-chips.com> wrote:
> The bus clock and function clock are separated at rk3399,
> and others use one clock as the bus clock and function clock.
>
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> ---
>  Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 16 +++++++++++++---
>  1 file changed, 13 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> index 0b4a85f..82b6f6b 100644
> --- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> +++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> @@ -6,10 +6,20 @@ RK3xxx SoCs.
>  Required properties :
>
>   - reg : Offset and length of the register set for the device
> - - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c",
> -               "rockchip,rk3228-i2c" or "rockchip,rk3288-i2c".
> + - compatible: should be one of the followings
> +   - "rockchip,rk3066-i2c": for rk3066
> +   - "rockchip,rk3188-i2c": for rk3188
> +   - "rockchip,rk3228-i2c": for rk3228
> +   - "rockchip,rk3288-i2c": for rk3288
> +   - "rockchip,rk3399-i2c": for rk3399
>   - interrupts : interrupt number
> - - clocks : parent clock
> + - clocks: See ../clock/clock-bindings.txt
> +   - For older hardware (rk3066, rk3188, rk3228, rk3288):
> +     - There is one clock that's used both to derive the functional clock
> +       for the device and as the bus clock.  REQUIRED.
> +   - For newer hardware (rk3399): specify by name
> +     - "i2c": REQUIRED. This is used to derive the functional clock.
> +     - "pclk": REQUIRED. This is the bus clock.equired on RK3066, RK3188 :

Looks great except that you need to delete the "equired on RK3066,
RK3188 :" part, which looks like it was leftover from some sort of
copy/paste.

Once that is done, feel free to add my Reviewed-by tag.


-Doug


From dianders at chromium.org  Thu May  5 16:00:56 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 5 May 2016 16:00:56 -0700
Subject: [PATCH v7 8/9] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <1462372609-6535-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372609-6535-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=VhMJiowNWm+0=jzzK0vajg1=3PutaWbzhGPN_BU2+19w@mail.gmail.com>

David,

On Wed, May 4, 2016 at 7:36 AM, David Wu <david.wu at rock-chips.com> wrote:
> +/**
> + * Calculate timing values for desired SCL frequency
> + *
> + * @clk_rate: I2C input clock rate
> + * @t: Known I2C timing information
> + * @t_calc: Caculated rk3x private timings that would be written into regs
> +
> + * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
> + * a best-effort divider value is returned in divs. If the target rate is
> + * too high, we silently use the highest possible rate.
> + * The following formulas are v1's method to calculate timings.
> + *
> + * l = divl + 1;
> + * h = divh + 1;
> + * s = sda_update_config + 1;
> + * u = start_setup_config + 1;
> + * p = stop_setup_config + 1;
> + * T = Tclk_i2c;
> +
> + * tHigh = 8 * h * T;
> + * tLow = 8 * l * T;
> +
> + * tHD;sda = (l * s + 1) * T;
> + * tSU;sda = [(8 - s) * l + 1] * T;
> + * tI2C = 8 * (l + h) * T;
> +
> + * tSU;sta = (8h * u + 1) * T;
> + * tHD;sta = [8h * (u + 1) - 1] * T;
> + * tSU;sto = (8h * p + 1) * T;
> + */
> +static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
> +                                   struct i2c_timings *t,
> +                                   struct rk3x_i2c_calced_timings *t_calc)
> +{

I don't think I'm going to try to understand all the math here.  I'll
trust you that this does something sane.


> +       /* Final divh and divl must be greater than 0, otherwise the
> +        * hardware would not output the i2c clk.
> +        */

nit: multiline comment style doesn't match rest of file.


>  static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
>  {
>         struct i2c_timings *t = &i2c->t;
> -       struct rk3x_i2c_calced_timings calc;
> +       struct rk3x_i2c_calced_timings *calc = &i2c->t_calc;
>         u64 t_low_ns, t_high_ns;
>         int ret;
>
> -       ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
> +       ret = i2c->soc_data->calc_timings(clk_rate, t, calc);
>         WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
>
> -       clk_enable(i2c->clk);
> -       i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
> +       if (i2c->pclk)
> +               clk_enable(i2c->pclk);
> +       else
> +               clk_enable(i2c->clk);
> +       i2c_writel(i2c, (calc->div_high << 16) | (calc->div_low & 0xffff),
>                    REG_CLKDIV);

There is a subtle bug here, though it likely doesn't manifest in any
current hardware configurations.

Specifically if you get a clock change on a device with a "v1"
controller while an i2c transaction is happening then you will likely
get i2c errors.

The clock change notifications work like this:
* Before the clock change, adjust the timings based on the faster of
the old/new clock.
* Let the clock change happen.
* If we didn't adjust the timings before, adjust them now.

With the logic above there will be a period where the i2c transaction
is happening slower than ideal, but that should be OK.  ...and you can
imagine the speed of the transaction changing midway through the
transaction--even midway through a single byte.


With v1 some of the timing information is _not_updated by
rk3x_i2c_adapt_div()--it's only set at the start of a transaction.
That breaks all the above assumptions.

So you should probably be updating the the RKI2C_CON register here by
doing a read-modify-write, like:

ctrl = i2c_readl(i2c, REG_CON);
ctrl &= ~REG_CON_TUNING_MASK;
ctrl |= i2c->t_calc.tuning;
i2c_writel(i2c, ctrl, REG_CON);


Also (optional): once you do that, there becomes much less of a reason
to store "t_calc" in "struct rk3x_i2c".  Already you're never using
the "div_low" and "div_high" that you store in the "struct rk3x_i2c".
Of course, to do that you've got to change other places not to clobber
these bits in REG_CON.


> @@ -728,11 +910,11 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
>  {
>         struct clk_notifier_data *ndata = data;
>         struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
> -       struct rk3x_i2c_calced_timings calc;
>
>         switch (event) {
>         case PRE_RATE_CHANGE:
> -               if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0)
> +               if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t,
> +                                               &i2c->t_calc) != 0)

This change is incorrect.  Please change it back to being calculated
in a local variable.  Optionally also add a comment that says:

/*
 * Try the calculation (but don't store the result) ahead of
 * time to see if we need to block the clock change.  Timings
 * shouldn't actually take effect until rk3x_i2c_adapt_div().
 */

Specifically in the case that we return NOTIFY_STOP here we _don't_
want to have modified our internal timings.  We also _don't_ want to
have modified our internal timings in the case that the old_rate > the
new_rate.

BTW: Did you manage to find anyone using an old Rockchip SoC that can
test your patches?


> @@ -1042,17 +1236,38 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
>
>         platform_set_drvdata(pdev, i2c);
>
> +       i2c->clk = devm_clk_get(&pdev->dev, NULL);
> +       if (IS_ERR(i2c->clk)) {
> +               dev_err(&pdev->dev, "cannot get clock\n");
> +               return PTR_ERR(i2c->clk);
> +       }
> +
>         ret = clk_prepare(i2c->clk);
>         if (ret < 0) {
>                 dev_err(&pdev->dev, "Could not prepare clock\n");
>                 return ret;
>         }
>
> +       if (i2c->soc_data->calc_timings == rk3x_i2c_v1_calc_timings) {
> +               i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
> +               if (IS_ERR(i2c->pclk)) {
> +                       dev_err(i2c->dev, "Could not get i2c pclk\n");
> +                       ret = PTR_ERR(i2c->pclk);
> +                       goto err_clk;
> +               }
> +
> +               ret = clk_prepare(i2c->pclk);
> +               if (ret) {
> +                       dev_err(i2c->dev, "Could not prepare pclk\n");
> +                       goto err_clk;
> +               }
> +       }

This is not matching the bindings.  You are still assuming that "i2c"
clock is the first clock and "pclk" is the one named "pclk".  Said
another way, if you had the following in your device tree:

  clocks =  <&pmucru PCLK_I2C0_PMU>, <&pmucru SCLK_I2C0_PMU>;
  clock-names = "pclk", "i2c";

...you'll find that you'll get back "pclk" twice.  The first time
you'll get it because you asked for the first clock listed, the second
time because you asked for the clock named "pclk".

I'd also say that your life will probably be easier if you always
setup both "clk" and "pclk", even on old CPUs.  It's OK to call
"clk_prepare" twice and OK to call "clk_enable" twice.

Thus, I'd probably write all the code as this (untested):

  if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) {
    /* Only one clock to use for bus clock and peripheral clock */
    i2c->clk = devm_clk_get(&pdev->dev, NULL);
    i2c->pclk = i2c->clk;
  } else {
    i2c->clk = devm_clk_get(&pdev->dev, "i2c");
    i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
  }
  if (IS_ERR(i2c->clk)) {
    ret = PTR_ERR(i2c->clk);
    if (ret != -EPROBE_DEFER)
      dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret);
    return ret;
  }
  if (IS_ERR(i2c->pclk)) {
    ret = PTR_ERR(i2c->pclk);
    if (ret != -EPROBE_DEFER)
      dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret);
    return ret;
  }
  ret = clk_prepare(i2c->clk);
  if (ret < 0) {
    dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret);
    return ret;
  }
  ret = clk_prepare(i2c->pclk);
  if (ret < 0) {
    dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret);
    goto err_clk;
  }

If you take that advice, you can get rid of all of the "if
(i2c->pclk)" statements in your code.


-Doug


From dianders at chromium.org  Thu May  5 16:02:16 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 5 May 2016 16:02:16 -0700
Subject: [PATCH v7 9/9] i2c: rk3x: support fast-mode plus for rk3399
In-Reply-To: <1462372668-6583-1-git-send-email-david.wu@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372668-6583-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=UtHPDtB7LTbUpwcjOcoYwNma59-TRDU3hrt6c_2TWxxA@mail.gmail.com>

David,

On Wed, May 4, 2016 at 7:37 AM, David Wu <david.wu at rock-chips.com> wrote:
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> ---
>  drivers/i2c/busses/i2c-rk3x.c | 21 +++++++++++++++++----
>  1 file changed, 17 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
> index 47368c4..c66cc39 100644
> --- a/drivers/i2c/busses/i2c-rk3x.c
> +++ b/drivers/i2c/busses/i2c-rk3x.c
> @@ -124,6 +124,17 @@ static const struct i2c_spec_values fast_mode_spec = {
>         .min_hold_buffer_ns = 1300,
>  };
>
> +static const struct i2c_spec_values fast_mode_plus_spec = {
> +       .min_hold_start_ns = 260,
> +       .min_low_ns = 500,
> +       .min_high_ns = 260,
> +       .min_setup_start_ns = 260,
> +       .max_data_hold_ns = 400,

I'm curious where you got the data_hold_ns.  I can't quite remember
what this parameter does / how the timing function works anymore, but
the doc I have (search for UM10204 and click the first link) shows
values for Standard-mode and Fast-mode but not Fast-mode Plus.  It
seems to imply that this is a bit of a bogus number anyway because it
only matters if we don't stretch the tLOW to go along with the longer
data hold.

As I have said in the previous patch, how all this stuff works has
totally left my brain, so if you understand it that's probably good
enough.  If you feel like I should try to re-understand this again so
I can review it more deeply, let me know.


Since I assume that you had some sane reason to include max_data_hold_ns:

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Thu May  5 17:35:03 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 5 May 2016 17:35:03 -0700
Subject: [RFC PATCH 2/3] clk: adjust clocks to their requested rate after
 parent changes
In-Reply-To: <1462206982-10444-3-git-send-email-heiko@sntech.de>
References: <1462206982-10444-1-git-send-email-heiko@sntech.de>
 <1462206982-10444-3-git-send-email-heiko@sntech.de>
Message-ID: <CAD=FV=X6at49s-8Wh3+RnLwNQr5RqDMvfJJF+TwvuhnurmQk1w@mail.gmail.com>

Heiko,

On Mon, May 2, 2016 at 9:36 AM, Heiko Stuebner <heiko at sntech.de> wrote:
> Given a hirarchy of clk1 -> [div] -> clk2, when the rate of clk1 gets
> changed, clk2 changes as well as the divider stays the same. There may
> be cases where a user of clk2 needs it at a specific rate, so clk2
> needs to be readjusted for the changed rate of clk1.
>
> So if a rate was requested for the clock, and its rate changed during
> the underlying rate-change, with this change the clock framework now
> tries to readjust the rate back to/near the requested one.
>
> The whole process is protected by a new clock-flag to not force this
> behaviour change onto every clock defined in the ccf.

I'm not an expert on CCF details, but presumably you need to be really
careful here.  Is there any way you could get an infinite loop here
where you ping-pong between two people trying to control their parent
clock?  Right now I see mutual recursion between
clk_core_set_rate_nolock() and clk_change_rate() and no base case.

Specifically if there's a path (because of CLK_SET_RATE_PARENT) where
setting a clock rate on "clk2" in your example can cause a rate change
of "clk1" I worry that we'll be in trouble.  Maybe a requirement of
your patch is that no such path exists?  ...or maybe something in the
code prevents this...


> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> ---
>  drivers/clk/clk.c            | 13 +++++++++++--
>  include/linux/clk-provider.h |  1 +
>  2 files changed, 12 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> index 65e0aad..22be369 100644
> --- a/drivers/clk/clk.c
> +++ b/drivers/clk/clk.c
> @@ -1410,6 +1410,9 @@ static struct clk_core *clk_propagate_rate_change(struct clk_core *core,
>         return fail_clk;
>  }
>
> +static int clk_core_set_rate_nolock(struct clk_core *core,
> +                                   unsigned long req_rate);
> +
>  /*
>   * walk down a subtree and set the new rates notifying the rate
>   * change on the way
> @@ -1494,6 +1497,12 @@ static void clk_change_rate(struct clk_core *core)
>         /* handle the new child who might not be in core->children yet */
>         if (core->new_child)
>                 clk_change_rate(core->new_child);
> +
> +       /* handle a changed clock that needs to readjust its rate */
> +       if (core->flags & CLK_KEEP_REQ_RATE && core->req_rate
> +                                           && core->new_rate != old_rate
> +                                           && core->new_rate != core->req_rate)
> +               clk_core_set_rate_nolock(core, core->req_rate);

I guess we don't care about errors here?

...maybe (?) we could ignore errors if we validated this rate change
with PRE_RATE_CHANGE before attempting to change the parent clock, but
I don't see the code doing this unless I missed it.


>  }
>
>  static int clk_core_set_rate_nolock(struct clk_core *core,
> @@ -1529,11 +1538,11 @@ static int clk_core_set_rate_nolock(struct clk_core *core,
>                 return -EBUSY;
>         }
>
> +       core->req_rate = req_rate;
> +
>         /* change the rates */
>         clk_change_rate(top);
>
> -       core->req_rate = req_rate;
> -
>         return ret;
>  }
>
> diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> index 0c72204..06f189e 100644
> --- a/include/linux/clk-provider.h
> +++ b/include/linux/clk-provider.h
> @@ -33,6 +33,7 @@
>  #define CLK_RECALC_NEW_RATES   BIT(9) /* recalc rates after notifications */
>  #define CLK_SET_RATE_UNGATE    BIT(10) /* clock needs to run to set rate */
>  #define CLK_IS_CRITICAL                BIT(11) /* do not gate, ever */
> +#define CLK_KEEP_REQ_RATE      BIT(12) /* keep reqrate on parent rate change */

s/reqrate/req_rate/


From dianders at google.com  Thu May  5 17:46:59 2016
From: dianders at google.com (Doug Anderson)
Date: Thu, 5 May 2016 17:46:59 -0700
Subject: [RFC PATCH 0/3] clk: attempt to keep requested rate on parent
 changes
In-Reply-To: <4828628.D4nfByUg7D@diego>
References: <1462206982-10444-1-git-send-email-heiko@sntech.de>
 <572B4AF8.6070509@collabora.com> <4828628.D4nfByUg7D@diego>
Message-ID: <CAD=FV=XFGHqB8RY1TwMBPds_kLjjxwMHiAAf-Mnzf6NCOvVCHg@mail.gmail.com>

Hi,

On Thu, May 5, 2016 at 8:07 AM, Heiko St?bner <heiko at sntech.de> wrote:
>> Besides that, do you know already if it would solve the conflicts
>> described by Doug in the thread below?
>>
>> http://thread.gmane.org/gmane.linux.kernel/1820653/focus=3298
>
> I think the big issue on the rk3288 is, who is actually in charge of
> controlling the npll frequency.
>
> On the rk3399 the vpll is supplied unmodified to the hdmiphy, while as a
> dclk_vop source it goes through a divider first. So it's pretty clear that the
> hdmiphy will control the core frequency while other users need to adapt to
> what they get.
>
> On the rk3288 the npll is a possible source to both the hdmi- as well as the
> edp-clock (and some others as well), so when it gets adapted dynamically, wo
> is going to be in charge and who needs to adapt ... and how do we set this
> hierarchy.

Yeah, I don't think it fully solves the rk3288 problem, though
probably you'd end up in a better shape than today.

Specifically:

1. It assumes that the last requester of the rate is the one who gets
to specify it.  That's fine in the master-slave relationship that
Heiko describes for rk3399, but not so great for the peer-peer
relationship of NPLL uses on rk3288.  Said another way: on rk3399 it's
clear that HDMI decides the rate and the VOP has to deal with it, but
on rk3288 you've got two equals both wanting their own rate.

2. It's unclear exactly how well the different users of the VOP would
be able to cope with arbitrary rate changes since it really depends on
what's connected on the other end.


In general it seems like the rule for two peers should be that the
first requester should keep its rate and the 2nd requester should just
have to deal with it, unless the first requester added special code to
validate that the new rate was OK.

-Doug


From dianders at chromium.org  Thu May  5 17:49:39 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 5 May 2016 17:49:39 -0700
Subject: [RFC PATCH 2/3] clk: adjust clocks to their requested rate after
 parent changes
In-Reply-To: <CAD=FV=X6at49s-8Wh3+RnLwNQr5RqDMvfJJF+TwvuhnurmQk1w@mail.gmail.com>
References: <1462206982-10444-1-git-send-email-heiko@sntech.de>
 <1462206982-10444-3-git-send-email-heiko@sntech.de>
 <CAD=FV=X6at49s-8Wh3+RnLwNQr5RqDMvfJJF+TwvuhnurmQk1w@mail.gmail.com>
Message-ID: <CAD=FV=WegPb3AMsUM+Rx_uZ3sMCGUFz-vEh_8WDTqTp1MHWOUQ@mail.gmail.com>

Hi,

On Thu, May 5, 2016 at 5:35 PM, Doug Anderson <dianders at chromium.org> wrote:
> I guess we don't care about errors here?
>
> ...maybe (?) we could ignore errors if we validated this rate change
> with PRE_RATE_CHANGE before attempting to change the parent clock, but
> I don't see the code doing this unless I missed it.

One other related thought: it seems like there should be code
_somewhere_ that decides whether to adjust the child dividers before
or after the parent clock changes.  Specifically if the parent clock
is increasing in speed we probably want to slow down the child clock
ahead of the parent's increase.  I don't see such code here, but again
I'm pretty good at missing things unless they are slapping me in the
face.  ;)

-Doug


From computersforpeace at gmail.com  Thu May  5 18:02:44 2016
From: computersforpeace at gmail.com (Brian Norris)
Date: Thu,  5 May 2016 18:02:44 -0700
Subject: [PATCH] ARM: dts: rk3288: add SPI flash node for veyron
Message-ID: <1462496564-76530-1-git-send-email-computersforpeace@gmail.com>

This is a standard binding for describing SPI flash that can be
identified by reading their JEDEC ID. Let's use it.

Tested on Veyron Jaq.

Signed-off-by: Brian Norris <computersforpeace at gmail.com>
---
 arch/arm/boot/dts/rk3288-veyron.dtsi | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/arm/boot/dts/rk3288-veyron.dtsi b/arch/arm/boot/dts/rk3288-veyron.dtsi
index 412809c60d01..28f8ba8ae500 100644
--- a/arch/arm/boot/dts/rk3288-veyron.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron.dtsi
@@ -369,6 +369,12 @@
 	status = "okay";
 
 	rx-sample-delay-ns = <12>;
+
+	flash at 0 {
+		compatible = "jedec,spi-nor";
+		spi-max-frequency = <50000000>;
+		reg = <0>;
+	};
 };
 
 &tsadc {
-- 
2.8.0.rc3.226.g39d4020



From david.wu at rock-chips.com  Thu May  5 19:12:04 2016
From: david.wu at rock-chips.com (David.Wu)
Date: Fri, 6 May 2016 10:12:04 +0800
Subject: [PATCH v7 9/9] i2c: rk3x: support fast-mode plus for rk3399
In-Reply-To: <CAD=FV=UtHPDtB7LTbUpwcjOcoYwNma59-TRDU3hrt6c_2TWxxA@mail.gmail.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372668-6583-1-git-send-email-david.wu@rock-chips.com>
 <CAD=FV=UtHPDtB7LTbUpwcjOcoYwNma59-TRDU3hrt6c_2TWxxA@mail.gmail.com>
Message-ID: <572BFD74.9080200@rock-chips.com>

Hi Doug,

? 2016/5/6 7:02, Doug Anderson ??:
> David,
>
> On Wed, May 4, 2016 at 7:37 AM, David Wu <david.wu at rock-chips.com> wrote:
>> Signed-off-by: David Wu <david.wu at rock-chips.com>
>> ---
>>   drivers/i2c/busses/i2c-rk3x.c | 21 +++++++++++++++++----
>>   1 file changed, 17 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
>> index 47368c4..c66cc39 100644
>> --- a/drivers/i2c/busses/i2c-rk3x.c
>> +++ b/drivers/i2c/busses/i2c-rk3x.c
>> @@ -124,6 +124,17 @@ static const struct i2c_spec_values fast_mode_spec = {
>>          .min_hold_buffer_ns = 1300,
>>   };
>>
>> +static const struct i2c_spec_values fast_mode_plus_spec = {
>> +       .min_hold_start_ns = 260,
>> +       .min_low_ns = 500,
>> +       .min_high_ns = 260,
>> +       .min_setup_start_ns = 260,
>> +       .max_data_hold_ns = 400,
>
> I'm curious where you got the data_hold_ns.  I can't quite remember
> what this parameter does / how the timing function works anymore, but
> the doc I have (search for UM10204 and click the first link) shows
> values for Standard-mode and Fast-mode but not Fast-mode Plus.  It
> seems to imply that this is a bit of a bogus number anyway because it
> only matters if we don't stretch the tLOW to go along with the longer
> data hold.
>
> As I have said in the previous patch, how all this stuff works has
> totally left my brain, so if you understand it that's probably good
> enough.  If you feel like I should try to re-understand this again so
> I can review it more deeply, let me know.
>
>

Yes, I could not get the description of fast-mode plus data_hold_ns, but 
I saw that the maximum tHD;DAT must be less than the maximum of 
tVD;DATor tVD;ACKby for Standard-mode and Fast-mode.

So I think the maximum tHD;DAT for Fast-mode Plus should be less than 
the maximum of tVD;DATor tVD;ACKby too, the maximum of tVD;DATor 
tVD;ACKby is 450ns, and 400ns is my taking a conservative value.

Description form UM10204
[4] The maximum tHD;DATcould be 3.45?s and 0.9?s for Standard-mode and 
Fast-mode, but must be less than the maximum of tVD;DATor tVD;ACKby a 
transition time. This maximum must only be met if the device does not 
stretch the LOW period (tLOW) of the SCL signal. If the clock stretches 
the SCL, the data must be valid by the set-up time before it releases
the clock.

> Since I assume that you had some sane reason to include max_data_hold_ns:
>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>
>
>
>



From david.wu at rock-chips.com  Thu May  5 19:19:13 2016
From: david.wu at rock-chips.com (David.Wu)
Date: Fri, 6 May 2016 10:19:13 +0800
Subject: [PATCH v7 2/9] i2c: rk3x: use struct "rk3x_i2c_calced_timings"
In-Reply-To: <CAD=FV=WAbedAB78shifxwjmZ-od8rhOiNz80rpdqfwzRsdX6WQ@mail.gmail.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462371194-5809-3-git-send-email-david.wu@rock-chips.com>
 <CAD=FV=WAbedAB78shifxwjmZ-od8rhOiNz80rpdqfwzRsdX6WQ@mail.gmail.com>
Message-ID: <572BFF21.6060500@rock-chips.com>

Hi Doug,

? 2016/5/6 6:55, Doug Anderson ??:
> David,
>
> On Wed, May 4, 2016 at 7:13 AM, David Wu <david.wu at rock-chips.com> wrote:
>> Signed-off-by: David Wu <david.wu at rock-chips.com>
>
> Usually folks like a description and not just a subject line.  I'd add
> a description like:
>
> The "div_high" and "div_low" values are always used together.  Group them
> into a structure to make it easier to pass them both around.  This
> structure also provides a place for future calculated timings.
>

Okay, i will add it in next version, thanks.

>> ---
>> Change in v7:
>> - none
>>
>>   drivers/i2c/busses/i2c-rk3x.c | 55 +++++++++++++++++++++++++------------------
>>   1 file changed, 32 insertions(+), 23 deletions(-)
>
> Other than the description, I think this looks fine.
>
> IMHO this can be applied any time independent of any earlier patches.
>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>
>
>
>



From david.wu at rock-chips.com  Thu May  5 20:20:41 2016
From: david.wu at rock-chips.com (David.Wu)
Date: Fri, 6 May 2016 11:20:41 +0800
Subject: [PATCH v7 4/9] i2c: rk3x: Move setting STATE_START and add
 STATE_SETUP
In-Reply-To: <CAD=FV=WVKpJJbqc=UYbeObDurjte0iQOzvLL++i=wM9=TBeCDQ@mail.gmail.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462371194-5809-5-git-send-email-david.wu@rock-chips.com>
 <CAD=FV=WVKpJJbqc=UYbeObDurjte0iQOzvLL++i=wM9=TBeCDQ@mail.gmail.com>
Message-ID: <572C0D89.9050708@rock-chips.com>

Hi Doug,

? 2016/5/6 6:56, Doug Anderson ??:
> David,
>
> On Wed, May 4, 2016 at 7:13 AM, David Wu <david.wu at rock-chips.com> wrote:
>> Signed-off-by: David Wu <david.wu at rock-chips.com>
>> ---
>> Change in v7:
>> - none
>>
>>   drivers/i2c/busses/i2c-rk3x.c | 5 ++++-
>>   1 file changed, 4 insertions(+), 1 deletion(-)
>
> Probably this change could be dropped now.  Switching the location of
> setting START_START was much more important when you were supporting
> HIGH SPEED mode.  I don't think we need it anymore, right?
>

Yes, I would drop it next version?STATE_SETUP didn't make sense, it was
not much more important, because there was a error printk for 
rk3x_i2c_setup() called failed.

> ...if we want to keep this change, I'd say:
>
> 1. Add a description, like maybe:
>
> To help with debugging add a STATE_SETUP between STATE_IDLE and
> STATE_START to make it more obvious that we're not actually idle but we
> also haven't initiated the start bit.  This change is not expected to
> have any impact but it does delay the changing of state to STATE_START.
> If previously we were getting an erroneous interrupt before we actually
> sent the start bit we'll now be treating that differently.  The new
> behavior (catching the erroneous interrupt) should be better.
>
> 2. Change "i2c->state = STATE_SETUP" to the _start_ of
> rk3x_i2c_setup().  That would have a better chance of catching a
> spurious interrupt.
>
> 3. Add an error check at the start of rk3x_i2c_irq() similar to the
> check for STATE_IDLE (or use the same check and modify the printk).
> Specifically the justification for adding STATE_SETUP is to help with
> debugging (catch interrupts that were unexpected and print more info
> about our state), so we should make it useful for this.
>
>
> -Doug
>
>
>



From david.wu at rock-chips.com  Thu May  5 21:55:15 2016
From: david.wu at rock-chips.com (David.Wu)
Date: Fri, 6 May 2016 12:55:15 +0800
Subject: [PATCH v7 6/9] i2c: rk3x: Move spec timing data to "static const"
 structs
In-Reply-To: <CAD=FV=Vg+umhA73uR66AdFmaNKhpyXCYojqE9kZJqkTOsyK_Jg@mail.gmail.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372472-6396-1-git-send-email-david.wu@rock-chips.com>
 <CAD=FV=Vg+umhA73uR66AdFmaNKhpyXCYojqE9kZJqkTOsyK_Jg@mail.gmail.com>
Message-ID: <572C23B3.6090702@rock-chips.com>

Hi Doug,

? 2016/5/6 6:58, Doug Anderson ??:
> David,
>
> On Wed, May 4, 2016 at 7:34 AM, David Wu <david.wu at rock-chips.com> wrote:
>> Signed-off-by: David Wu <david.wu at rock-chips.com>
>
> As you can probably guess, again a description would be nice.  Like maybe:
>
> The i2c timing specs are really just constant data.  There's no reason
> to write code to init them, so move them out to structures.  This not
> only is a cleaner solution but it will reduce code duplication when we
> introduce a new variant of rk3x_i2c_calc_divs() in a future patch.
>
> That helps someone reading the patch understand the motivation.
>
>
>> @@ -76,6 +76,51 @@ enum {
>>   #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
>>
>>   /**
>> + * struct i2c_spec_values:
>> + * @min_hold_start_ns: min hold time (repeated) START condition
>> + * @min_low_ns: min LOW period of the SCL clock
>> + * @min_high_ns: min HIGH period of the SCL cloc
>> + * @min_setup_start_ns: min set-up time for a repeated START conditio
>> + * @max_data_hold_ns: max data hold time
>> + * @min_data_setup_ns: min data set-up time
>> + * @min_setup_stop_ns: min set-up time for STOP condition
>> + * @min_hold_buffer_ns: min bus free time between a STOP and
>> + * START condition
>> + */
>> +struct i2c_spec_values {
>> +       unsigned long min_hold_start_ns;
>> +       unsigned long min_low_ns;
>> +       unsigned long min_high_ns;
>> +       unsigned long min_setup_start_ns;
>> +       unsigned long max_data_hold_ns;
>> +       unsigned long min_data_setup_ns;
>> +       unsigned long min_setup_stop_ns;
>> +       unsigned long min_hold_buffer_ns;
>> +};
>> +
>> +static const struct i2c_spec_values standard_mode_spec = {
>> +       .min_hold_start_ns = 4000,
>> +       .min_low_ns = 4700,
>> +       .min_high_ns = 4000,
>> +       .min_setup_start_ns = 4700,
>> +       .max_data_hold_ns = 3450,
>> +       .min_data_setup_ns = 250,
>> +       .min_setup_stop_ns = 4000,
>> +       .min_hold_buffer_ns = 4700,
>
> There are more spec values than are currently used in this patch.
> Personally I'm OK with that, but if you wanted to be totally clean
> this patch would only include the spec values that were needed, then
> introduce the additional values in the rk3399 patch.
>
>
>> @@ -492,6 +548,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
>>          unsigned long min_div_for_hold, min_total_div;
>>          unsigned long extra_div, extra_low_div, ideal_low_div;
>>
>> +       unsigned long data_hold_buffer_ns = 50;
>
> aside (feel free to ignore): Gosh, I kinda forgot what the heck this
> value was for.  I guess it's not anything in the spec.  I have a
> feeling it was some sort of slop value that someone felt was
> necessary, but I don't quite remember.  Oh well, I guess we leave it
> there since I'd rather not mess with timings on old hardware that are
> apparently working for everyone.  :-P
>
>

I thing it was a tuning value for max_t_low_ns. :-P

> In any case, aside from the missing description:
>
> Suggested-by: Douglas Anderson <dianders at chromium.org>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>
>
> IMHO this can be applied any time independent of any earlier patches.
>
>
> -Doug
>
>
>



From david.wu at rock-chips.com  Thu May  5 23:09:48 2016
From: david.wu at rock-chips.com (David.Wu)
Date: Fri, 6 May 2016 14:09:48 +0800
Subject: [PATCH v7 7/9] dt-bindings: i2c: rk3x: add support for rk3399
In-Reply-To: <20160505221212.GA26820@rob-hp-laptop>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372523-6444-1-git-send-email-david.wu@rock-chips.com>
 <20160505221212.GA26820@rob-hp-laptop>
Message-ID: <572C352C.50303@rock-chips.com>

Hi Rob,

? 2016/5/6 6:12, Rob Herring ??:
> On Wed, May 04, 2016 at 10:35:23PM +0800, David Wu wrote:
>> The bus clock and function clock are separated at rk3399,
>> and others use one clock as the bus clock and function clock.
>>
>> Signed-off-by: David Wu <david.wu at rock-chips.com>
>> ---
>>   Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 16 +++++++++++++---
>>   1 file changed, 13 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
>> index 0b4a85f..82b6f6b 100644
>> --- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
>> +++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
>> @@ -6,10 +6,20 @@ RK3xxx SoCs.
>>   Required properties :
>>
>>    - reg : Offset and length of the register set for the device
>> - - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c",
>> -		"rockchip,rk3228-i2c" or "rockchip,rk3288-i2c".
>> + - compatible: should be one of the followings
>
> s/followings/following:/
>
>> +   - "rockchip,rk3066-i2c": for rk3066
>> +   - "rockchip,rk3188-i2c": for rk3188
>> +   - "rockchip,rk3228-i2c": for rk3228
>> +   - "rockchip,rk3288-i2c": for rk3288
>> +   - "rockchip,rk3399-i2c": for rk3399
>>    - interrupts : interrupt number
>> - - clocks : parent clock
>> + - clocks: See ../clock/clock-bindings.txt
>> +   - For older hardware (rk3066, rk3188, rk3228, rk3288):
>> +     - There is one clock that's used both to derive the functional clock
>> +       for the device and as the bus clock.  REQUIRED.
>
> This is the required section, so REQUIRED is redundant.


>
>> +   - For newer hardware (rk3399): specify by name
>> +     - "i2c": REQUIRED. This is used to derive the functional clock.
>> +     - "pclk": REQUIRED. This is the bus clock.equired on RK3066, RK3188 :
>
> This doesn't make sense. The first line says this applies to rk3399, but
> then here it is talking about other parts.
>
> And there's a typo.
>

Okay, I will remove the "equired on RK3066, RK3188 :".

>>
>>   Required on RK3066, RK3188 :
>>
>> --
>> 1.9.1
>>
>>
>
>
>



From david.wu at rock-chips.com  Fri May  6 02:32:37 2016
From: david.wu at rock-chips.com (David.Wu)
Date: Fri, 6 May 2016 17:32:37 +0800
Subject: [PATCH v7 8/9] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <CAD=FV=VhMJiowNWm+0=jzzK0vajg1=3PutaWbzhGPN_BU2+19w@mail.gmail.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372609-6535-1-git-send-email-david.wu@rock-chips.com>
 <CAD=FV=VhMJiowNWm+0=jzzK0vajg1=3PutaWbzhGPN_BU2+19w@mail.gmail.com>
Message-ID: <572C64B5.6080607@rock-chips.com>

Hi Doug,

? 2016/5/6 7:00, Doug Anderson ??:
> David,
>
> On Wed, May 4, 2016 at 7:36 AM, David Wu <david.wu at rock-chips.com> wrote:
>> +/**
>> + * Calculate timing values for desired SCL frequency
>> + *
>> + * @clk_rate: I2C input clock rate
>> + * @t: Known I2C timing information
>> + * @t_calc: Caculated rk3x private timings that would be written into regs
>> +
>> + * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
>> + * a best-effort divider value is returned in divs. If the target rate is
>> + * too high, we silently use the highest possible rate.
>> + * The following formulas are v1's method to calculate timings.
>> + *
>> + * l = divl + 1;
>> + * h = divh + 1;
>> + * s = sda_update_config + 1;
>> + * u = start_setup_config + 1;
>> + * p = stop_setup_config + 1;
>> + * T = Tclk_i2c;
>> +
>> + * tHigh = 8 * h * T;
>> + * tLow = 8 * l * T;
>> +
>> + * tHD;sda = (l * s + 1) * T;
>> + * tSU;sda = [(8 - s) * l + 1] * T;
>> + * tI2C = 8 * (l + h) * T;
>> +
>> + * tSU;sta = (8h * u + 1) * T;
>> + * tHD;sta = [8h * (u + 1) - 1] * T;
>> + * tSU;sto = (8h * p + 1) * T;
>> + */
>> +static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
>> +                                   struct i2c_timings *t,
>> +                                   struct rk3x_i2c_calced_timings *t_calc)
>> +{
>
> I don't think I'm going to try to understand all the math here.  I'll
> trust you that this does something sane.
>
>
>> +       /* Final divh and divl must be greater than 0, otherwise the
>> +        * hardware would not output the i2c clk.
>> +        */
>
> nit: multiline comment style doesn't match rest of file.
>
>
>>   static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
>>   {
>>          struct i2c_timings *t = &i2c->t;
>> -       struct rk3x_i2c_calced_timings calc;
>> +       struct rk3x_i2c_calced_timings *calc = &i2c->t_calc;
>>          u64 t_low_ns, t_high_ns;
>>          int ret;
>>
>> -       ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
>> +       ret = i2c->soc_data->calc_timings(clk_rate, t, calc);
>>          WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
>>
>> -       clk_enable(i2c->clk);
>> -       i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
>> +       if (i2c->pclk)
>> +               clk_enable(i2c->pclk);
>> +       else
>> +               clk_enable(i2c->clk);
>> +       i2c_writel(i2c, (calc->div_high << 16) | (calc->div_low & 0xffff),
>>                     REG_CLKDIV);
>
> There is a subtle bug here, though it likely doesn't manifest in any
> current hardware configurations.
>
> Specifically if you get a clock change on a device with a "v1"
> controller while an i2c transaction is happening then you will likely
> get i2c errors.
>
> The clock change notifications work like this:
> * Before the clock change, adjust the timings based on the faster of
> the old/new clock.
> * Let the clock change happen.
> * If we didn't adjust the timings before, adjust them now.
>
> With the logic above there will be a period where the i2c transaction
> is happening slower than ideal, but that should be OK.  ...and you can
> imagine the speed of the transaction changing midway through the
> transaction--even midway through a single byte.
>
>
> With v1 some of the timing information is _not_updated by
> rk3x_i2c_adapt_div()--it's only set at the start of a transaction.
> That breaks all the above assumptions.
>
> So you should probably be updating the the RKI2C_CON register here by
> doing a read-modify-write, like:
>
> ctrl = i2c_readl(i2c, REG_CON);
> ctrl &= ~REG_CON_TUNING_MASK;
> ctrl |= i2c->t_calc.tuning;
> i2c_writel(i2c, ctrl, REG_CON);
>
>

Yeap, it seems it is a bug when a clock changes, but not update the 
regs, it might make transfer failed. It was not enough to just store 
tuning value.

> Also (optional): once you do that, there becomes much less of a reason
> to store "t_calc" in "struct rk3x_i2c".  Already you're never using
> the "div_low" and "div_high" that you store in the "struct rk3x_i2c".
> Of course, to do that you've got to change other places not to clobber
> these bits in REG_CON.
>

So, I only just need to store tuning value in the "struct rk3x_i2c", but 
not to store the "div_low" and "div_high"?
>
>> @@ -728,11 +910,11 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
>>   {
>>          struct clk_notifier_data *ndata = data;
>>          struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
>> -       struct rk3x_i2c_calced_timings calc;
>>
>>          switch (event) {
>>          case PRE_RATE_CHANGE:
>> -               if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0)
>> +               if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t,
>> +                                               &i2c->t_calc) != 0)
>
> This change is incorrect.  Please change it back to being calculated
> in a local variable.  Optionally also add a comment that says:
>
> /*
>   * Try the calculation (but don't store the result) ahead of
>   * time to see if we need to block the clock change.  Timings
>   * shouldn't actually take effect until rk3x_i2c_adapt_div().
>   */
>
> Specifically in the case that we return NOTIFY_STOP here we _don't_
> want to have modified our internal timings.  We also _don't_ want to
> have modified our internal timings in the case that the old_rate > the
> new_rate.

Okay, use &i2c->t_calc is an error here, timings shouldn't actually take 
effect until rk3x_i2c_adapt_div().

>
> BTW: Did you manage to find anyone using an old Rockchip SoC that can
> test your patches?
>

The patches we have already used in our projects, they are verified by 
the basic tests. I would ask them to do more tests. Because we didn't 
change the clock rate now, it was a fixed value when clk inited, so we 
could not find the bug here.

>
>> @@ -1042,17 +1236,38 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
>>
>>          platform_set_drvdata(pdev, i2c);
>>
>> +       i2c->clk = devm_clk_get(&pdev->dev, NULL);
>> +       if (IS_ERR(i2c->clk)) {
>> +               dev_err(&pdev->dev, "cannot get clock\n");
>> +               return PTR_ERR(i2c->clk);
>> +       }
>> +
>>          ret = clk_prepare(i2c->clk);
>>          if (ret < 0) {
>>                  dev_err(&pdev->dev, "Could not prepare clock\n");
>>                  return ret;
>>          }
>>
>> +       if (i2c->soc_data->calc_timings == rk3x_i2c_v1_calc_timings) {
>> +               i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
>> +               if (IS_ERR(i2c->pclk)) {
>> +                       dev_err(i2c->dev, "Could not get i2c pclk\n");
>> +                       ret = PTR_ERR(i2c->pclk);
>> +                       goto err_clk;
>> +               }
>> +
>> +               ret = clk_prepare(i2c->pclk);
>> +               if (ret) {
>> +                       dev_err(i2c->dev, "Could not prepare pclk\n");
>> +                       goto err_clk;
>> +               }
>> +       }
>
> This is not matching the bindings.  You are still assuming that "i2c"
> clock is the first clock and "pclk" is the one named "pclk".  Said
> another way, if you had the following in your device tree:
>
>    clocks =  <&pmucru PCLK_I2C0_PMU>, <&pmucru SCLK_I2C0_PMU>;
>    clock-names = "pclk", "i2c";
>
> ...you'll find that you'll get back "pclk" twice.  The first time
> you'll get it because you asked for the first clock listed, the second
> time because you asked for the clock named "pclk".
>
> I'd also say that your life will probably be easier if you always
> setup both "clk" and "pclk", even on old CPUs.  It's OK to call
> "clk_prepare" twice and OK to call "clk_enable" twice.
>
> Thus, I'd probably write all the code as this (untested):
>
>    if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) {
>      /* Only one clock to use for bus clock and peripheral clock */
>      i2c->clk = devm_clk_get(&pdev->dev, NULL);
>      i2c->pclk = i2c->clk;
>    } else {
>      i2c->clk = devm_clk_get(&pdev->dev, "i2c");
>      i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
>    }
>    if (IS_ERR(i2c->clk)) {
>      ret = PTR_ERR(i2c->clk);
>      if (ret != -EPROBE_DEFER)
>        dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret);
>      return ret;
>    }
>    if (IS_ERR(i2c->pclk)) {
>      ret = PTR_ERR(i2c->pclk);
>      if (ret != -EPROBE_DEFER)
>        dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret);
>      return ret;
>    }
>    ret = clk_prepare(i2c->clk);
>    if (ret < 0) {
>      dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret);
>      return ret;
>    }
>    ret = clk_prepare(i2c->pclk);
>    if (ret < 0) {
>      dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret);
>      goto err_clk;
>    }
>
> If you take that advice, you can get rid of all of the "if
> (i2c->pclk)" statements in your code.
>

It would make i2c->clk to be enabled and prepared twice when uses 
rk3x_i2c_v0_calc_timings for old hardware. But if do the opposite
disabled and unprepated twice, that is okay.

>
> -Doug
>
>
>



From shawn.lin at rock-chips.com  Fri May  6 02:40:48 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri,  6 May 2016 17:40:48 +0800
Subject: [PATCH 1/2] mmc: dw_mmc-rockchip: add default drv phase support
Message-ID: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>

This patch introduces default drv phase exposed to dts for
users to set drv phase. If default-drv-phase is not assigned,
let's set it to 180 degrees.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

 drivers/mmc/host/dw_mmc-rockchip.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 8c20b81..482eff1 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -24,6 +24,7 @@ struct dw_mci_rockchip_priv_data {
 	struct clk		*drv_clk;
 	struct clk		*sample_clk;
 	int			default_sample_phase;
+	int			default_drv_phase;
 };
 
 static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
@@ -66,6 +67,9 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 	/* Make sure we use phases which we can enumerate with */
 	if (!IS_ERR(priv->sample_clk))
 		clk_set_phase(priv->sample_clk, priv->default_sample_phase);
+
+	if (!IS_ERR(priv->drv_clk))
+		clk_set_phase(priv->drv_clk, priv->default_drv_phase);
 }
 
 #define NUM_PHASES			360
@@ -203,6 +207,10 @@ static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
 					&priv->default_sample_phase))
 		priv->default_sample_phase = 0;
 
+	if (of_property_read_u32(np, "rockchip,default-drv-phase",
+					&priv->default_drv_phase))
+		priv->default_drv_phase = 180;
+
 	priv->drv_clk = devm_clk_get(host->dev, "ciu-drive");
 	if (IS_ERR(priv->drv_clk))
 		dev_dbg(host->dev, "ciu_drv not available\n");
-- 
2.3.7




From shawn.lin at rock-chips.com  Fri May  6 02:41:13 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri,  6 May 2016 17:41:13 +0800
Subject: [PATCH 2/2] dt-bindings: rockchip-dw-mshc: add rockchip,
 default-drv-phase
In-Reply-To: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>

rockchip,default-drv-phase is used to set the default drv degrees.
drv phases will decide the write timing of mmc controller.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

 Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
index ea5614b..c48dba6 100644
--- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
@@ -29,6 +29,9 @@ Optional Properties:
   probing, low speeds or in case where all phases work at tuning time.
   If not specified 0 deg will be used.
 
+* rockchip,default-drv-phase: The default phase to set ciu_drv at probing
+  for host to write data to devices. If not specified 180 deg will be used.
+
 Example:
 
 	rkdwmmc0 at 12200000 {
-- 
2.3.7




From wxt at rock-chips.com  Fri May  6 05:19:16 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri,  6 May 2016 20:19:16 +0800
Subject: [PATCH v2] net: arc/emac: Move arc_emac_tx_clean() into arc_emac_tx()
 and disable tx interrut
Message-ID: <1462537156-10489-1-git-send-email-wxt@rock-chips.com>

From: Shuyu Wei <sy.w at outlook.com>

Doing tx_clean() inside poll() may scramble the tx ring buffer if
tx() is running. This will cause tx to stop working, which can be
reproduced by simultaneously downloading two large files at high speed.

Moving tx_clean() into tx() will prevent this. And tx interrupt is no
longer needed now.

Picked the Shuyu's patch up, the patch is sent on
https://patchwork.kernel.org/patch/8356821/, since that make sense for
rockchip platform.
Note: Many people feedback the cransh problems with rk3036/rk3188 emac when
download the heavy loading and this patch is indeed can fix the crash.

The crash log as the followings:
...
[ 2191.996127 ] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.4.0-rc6 #114
[ 2192.002475 ] Hardware name: Rockchip (Device Tree)
[ 2192.007174 ] Backtrace:
[ 2192.009658 ] [<c00134d4>] (dump_backtrace) from [<c0013680>]
    (show_stack+0x18/0x1c)
[ 2192.017220 ]  r7:c051c4f8 r6:ef463180 r5:c05b7000 r4:00000000
[ 2192.022948 ] [<c0013668>] (show_stack) from [<c0219d90>]
    (dump_stack+0x90/0xa0)
[ 2192.030176 ] [<c0219d00>] (dump_stack) from [<c00b2cd4>]
    (bad_page+0xdc/0x12c)
[ 2192.037302 ]  r5:c059a100 r4:c05f430c
[ 2192.040913 ] [<c00b2bf8>] (bad_page) from [<c00b606c>]
    (get_page_from_freelist+0x388/0x95c)
[ 2192.049166 ]  r9:00000008 r8:ef463180 r7:c051c4d0 r6:00000000
    r5:00000000 r4:c051c4e4
[ 2192.056982 ] [<c00b5ce4>] (get_page_from_freelist) from
[<c00b6880>] (__alloc_pages_nodemask+0xd8/0x8e8)
[ 2192.066362 ]  r10:c001b068 r9:00000000 r8:ee0b02b0 r7:60000113
    r6:00000003 r5:02095220
[ 2192.074254 ]  r4:c05ca1c0
[ 2192.076809 ] [<c00b67a8>] (__alloc_pages_nodemask) from
[<c00b7140>] (__alloc_page_frag+0xb0/0x160)
[ 2192.085757 ]  r10:c001b068 r9:00000000 r8:ee0b02b0 r7:60000113
    r6:02080020 r5:00000740
[ 2192.093650 ]  r4:eedbc884
[ 2192.096207 ] [<c00b7090>] (__alloc_page_frag) from [<c03273b4>]
    (__netdev_alloc_skb+0xa0/0x104)
[ 2192.104806 ]  r7:60000113 r6:eedbc884 r5:ee0b0000 r4:00000740
[ 2192.110525 ] [<c0327314>] (__netdev_alloc_skb) from [<c02aac00>]
    (arc_emac_poll+0x318/0x57c)
[ 2192.118865 ]  r9:00000000 r8:ee0b02b0 r7:0000019c r6:ee163780
    r5:00000670 r4:ee0b0000
[ 2192.126683 ] [<c02aa8e8>] (arc_emac_poll) from [<c0339ed8>]
    (net_rx_action+0x1f0/0x2ec)
[ 2192.134590 ]  r10:c0599df8 r9:c059a100 r8:00073760 r7:0000012c
    r6:00000028 r5:c02aa8e8
[ 2192.142483 ]  r4:ee0b04e0
[ 2192.145040 ] [<c0339ce8>] (net_rx_action) from [<c0026f5c>]
    (__do_softirq+0x134/0x258)
[ 2192.152860 ]  r10:c059a080 r9:40000003 r8:00000003 r7:00000100
    r6:c0598000 r5:c059a08c
[ 2192.160751 ]  r4:00000000
...

Signed-off-by: Shuyu Wei <sy.w at outlook.com>
Tested-by: Michael Niewoehner <linux at mniewoehner.de>
Tested-by: Xing Zheng <zhengxing at rock-chips.com>
Cc: "David S. Miller" <davem at davemloft.net>
Cc: Alexander Kochetkov <al.kochet at gmail.com>
Cc: netdev at vger.kernel.org
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
---

 drivers/net/ethernet/arc/emac_main.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index a3a9392..4f4e25e 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -311,12 +311,10 @@ static int arc_emac_poll(struct napi_struct *napi, int budget)
 	struct arc_emac_priv *priv = netdev_priv(ndev);
 	unsigned int work_done;
 
-	arc_emac_tx_clean(ndev);
-
 	work_done = arc_emac_rx(ndev, budget);
 	if (work_done < budget) {
 		napi_complete(napi);
-		arc_reg_or(priv, R_ENABLE, RXINT_MASK | TXINT_MASK);
+		arc_reg_or(priv, R_ENABLE, RXINT_MASK);
 	}
 
 	return work_done;
@@ -345,9 +343,9 @@ static irqreturn_t arc_emac_intr(int irq, void *dev_instance)
 	/* Reset all flags except "MDIO complete" */
 	arc_reg_set(priv, R_STATUS, status);
 
-	if (status & (RXINT_MASK | TXINT_MASK)) {
+	if (status & RXINT_MASK) {
 		if (likely(napi_schedule_prep(&priv->napi))) {
-			arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK);
+			arc_reg_clr(priv, R_ENABLE, RXINT_MASK);
 			__napi_schedule(&priv->napi);
 		}
 	}
@@ -461,7 +459,7 @@ static int arc_emac_open(struct net_device *ndev)
 	arc_reg_set(priv, R_TX_RING, (unsigned int)priv->txbd_dma);
 
 	/* Enable interrupts */
-	arc_reg_set(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK);
+	arc_reg_set(priv, R_ENABLE, RXINT_MASK | ERR_MASK);
 
 	/* Set CONTROL */
 	arc_reg_set(priv, R_CTRL,
@@ -594,7 +592,7 @@ static int arc_emac_stop(struct net_device *ndev)
 	netif_stop_queue(ndev);
 
 	/* Disable interrupts */
-	arc_reg_clr(priv, R_ENABLE, RXINT_MASK | TXINT_MASK | ERR_MASK);
+	arc_reg_clr(priv, R_ENABLE, RXINT_MASK | ERR_MASK);
 
 	/* Disable EMAC */
 	arc_reg_clr(priv, R_CTRL, EN_MASK);
@@ -656,6 +654,8 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
 	__le32 *info = &priv->txbd[*txbd_curr].info;
 	dma_addr_t addr;
 
+	arc_emac_tx_clean(ndev);
+
 	if (skb_padto(skb, ETH_ZLEN))
 		return NETDEV_TX_OK;
 
-- 
1.9.1



From dianders at chromium.org  Fri May  6 10:26:34 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 6 May 2016 10:26:34 -0700
Subject: [PATCH 2/2] dt-bindings: rockchip-dw-mshc: add rockchip,
 default-drv-phase
In-Reply-To: <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
 <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAD=FV=WSkBwBjVsRoDsfjD+sNfR70mKGRA0khjPKKW0zS2=PTw@mail.gmail.com>

Shawn,

On Fri, May 6, 2016 at 2:41 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> rockchip,default-drv-phase is used to set the default drv degrees.
> drv phases will decide the write timing of mmc controller.

Device tree bindings should probably have been patch 1/2, then the
code patch 2/2.


> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
>
>  Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt | 3 +++
>  1 file changed, 3 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
> index ea5614b..c48dba6 100644
> --- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
> +++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
> @@ -29,6 +29,9 @@ Optional Properties:
>    probing, low speeds or in case where all phases work at tuning time.
>    If not specified 0 deg will be used.
>
> +* rockchip,default-drv-phase: The default phase to set ciu_drv at probing
> +  for host to write data to devices. If not specified 180 deg will be used.

This is probably not right for a few reasons.

1. Specifying a single number for this property in terms of "degrees"
is probably not right.  The whole point of setting the "drive phase"
is to meet hold times, which are specified in the spec in terms of ns
in the spec and also specified differently for different SD/MMC speed
modes.  Note also that "phase" translates to very different delays (in
terms of ns) depending on the clock rate:

At 400 kHz, period is 2.5 us, so 90 degree phase offset is a delay of 625 ns
At 25 MHz, period is 40 ns, so a 90 degree phase offset represents a
delay of 10 ns.
At 50 MHz, period is 20 ns, so a 90 degree phase offset represents a
delay of 5 ns.
At 200 MHz, period is period is 5 ns, so a 90 degree phase offset
represents a delay of 1.25 ns.


2. As I understand it, the value needed for the drive phase is not
board specific unless you've got super crazy layout on a board (where
the clock line takes a very different path than everything else).
It's also not even terribly SoC-specific unless you've got some very
strange incarnation of dw_mmc that has very different internal delays
than everyone else.  Said another way, until we see an instance of an
SoC/board that really needs to do things special I'd say that we
should just implement this all in code (no device tree bindings).



3. If this property was actually board specific and actually needed to
be tuned board-by-board, you'd have a bug because your new device tree
bindings are not backward compatible and you'd probably be breaking
old boards.  Specifically you're changing the definition of what
happens when "rockchip,default-drv-phase" is not specified.  Old
behavior was to leave the value that was setup by the firmware (or
perhaps the hardware default if the firmware didn't touch this).

---

OK, so what should we do?

We could certainly do lots of crazy math to come up with the ideal
hold time for all different speed modes and all different types of
cards.  With my reading of the Designware Databook this would mean
that somewhere we'd want to specify which delay method we're using
(phase shift vs. delay line) and how long all the delays timings all
are on your particular SoC.  That all sounds quite difficult, though.

Probably you could just add a simple function that looked at the clock
and speed mode and always chose an offset of 90 or 180 degrees.  At
least on Rockchip devices you can be certain that you can make 90 and
180 degrees using phase shifts and thus the timings should be
consistent.  By default you could just always choose 180.  The
Designware databook has some examples where it picked 90 degrees
(SDR50, DDR50, SDR25, MMC High Speed), but I'm not enough of an MMC
expert to know if there is some benefit to choosing 90.  Would we
violate any specs if we just chose 180 degrees all the time everywhere
on all Rockchip devices?



-Doug


From dianders at chromium.org  Fri May  6 10:28:18 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 6 May 2016 10:28:18 -0700
Subject: [PATCH 1/2] mmc: dw_mmc-rockchip: add default drv phase support
In-Reply-To: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAD=FV=XZOJuD=kgSHQM3v63xtVGvxp4m-Y7KAzCRNkqy3tVSyA@mail.gmail.com>

Hi,

On Fri, May 6, 2016 at 2:40 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> This patch introduces default drv phase exposed to dts for
> users to set drv phase. If default-drv-phase is not assigned,
> let's set it to 180 degrees.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
>
>  drivers/mmc/host/dw_mmc-rockchip.c | 8 ++++++++
>  1 file changed, 8 insertions(+)

Replying to this patch in case someone isn't reading the bindings
patch.  See my reply there that it's probably wrong to specify it this
way in the device tree.  Let's continue the discussion there.

-Doug


From dianders at chromium.org  Fri May  6 11:00:02 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 6 May 2016 11:00:02 -0700
Subject: [PATCH v7 8/9] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <572C64B5.6080607@rock-chips.com>
References: <1462371194-5809-1-git-send-email-david.wu@rock-chips.com>
 <1462372609-6535-1-git-send-email-david.wu@rock-chips.com>
 <CAD=FV=VhMJiowNWm+0=jzzK0vajg1=3PutaWbzhGPN_BU2+19w@mail.gmail.com>
 <572C64B5.6080607@rock-chips.com>
Message-ID: <CAD=FV=XOOAbKxqJsxGU4pXbNJtbq_Q4Pj2=9P48NCze5NTJyrw@mail.gmail.com>

Hi

On Fri, May 6, 2016 at 2:32 AM, David.Wu <david.wu at rock-chips.com> wrote:
>> Also (optional): once you do that, there becomes much less of a reason
>> to store "t_calc" in "struct rk3x_i2c".  Already you're never using
>> the "div_low" and "div_high" that you store in the "struct rk3x_i2c".
>> Of course, to do that you've got to change other places not to clobber
>> these bits in REG_CON.
>>
>
> So, I only just need to store tuning value in the "struct rk3x_i2c", but not
> to store the "div_low" and "div_high"?

I was suggesting not adding anything to what's stored in "struct
rk3x_i2c" (AKA don't add t_calc there).  Just set the value directly
in the register here then change all other bits of code to respect it.

That is:

In rk3x_i2c_start(), write:

  u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;

In rk3x_i2c_xfer(), write:
  val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK
  val |= REG_CON_EN | REG_CON_STOP, REG_CON;
  i2c_writel(i2c, val);


You could get fancy and add a new "i2c_update_bits", but that might be overkill.


> The patches we have already used in our projects, they are verified by the
> basic tests. I would ask them to do more tests. Because we didn't change the
> clock rate now, it was a fixed value when clk inited, so we could not find
> the bug here.

OK.  Presumably a rk3066 w/ DVS enabled would be a good test?  Reading
the description of commit 249051f49907 ("i2c: rk3x: handle dynamic
clock rate changes correctly"), I see:

    The i2c input clock can change dynamically, e.g. on the RK3066 where
    pclk_i2c0 and pclk_i2c1 are connected to the armclk, which changes
    rate on cpu frequency scaling.


>> If you take that advice, you can get rid of all of the "if
>> (i2c->pclk)" statements in your code.
>>
>
> It would make i2c->clk to be enabled and prepared twice when uses
> rk3x_i2c_v0_calc_timings for old hardware. But if do the opposite
> disabled and unprepated twice, that is okay.

Right.  The same clock will get an enable / prepare count of "2"
(instead of two different clocks getting a count of "1).  ...but
nothing should be hurt by that.

-Doug


From sboyd at codeaurora.org  Fri May  6 15:55:43 2016
From: sboyd at codeaurora.org (Stephen Boyd)
Date: Fri, 6 May 2016 15:55:43 -0700
Subject: [PATCH 4/7] clk: rockchip: abstract pll get-params and
 set-params operations
In-Reply-To: <1461849075-8310-5-git-send-email-heiko@sntech.de>
References: <1461849075-8310-1-git-send-email-heiko@sntech.de>
 <1461849075-8310-5-git-send-email-heiko@sntech.de>
Message-ID: <20160506225543.GF3492@codeaurora.org>

On 04/28, Heiko Stuebner wrote:
> This moves the pll-specific get_params and set_params functions into a
> per-pll struct that gets associated at init time and will help us reign
> in some code duplication we're faced with right now.
> 
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> ---
>  drivers/clk/rockchip/clk-pll.c | 54 ++++++++++++++++++++++++++++++++----------
>  1 file changed, 42 insertions(+), 12 deletions(-)
> 
> diff --git a/drivers/clk/rockchip/clk-pll.c b/drivers/clk/rockchip/clk-pll.c
> index e56637d..2c30f52 100644
> --- a/drivers/clk/rockchip/clk-pll.c
> +++ b/drivers/clk/rockchip/clk-pll.c
> @@ -30,6 +30,14 @@
>  #define PLL_MODE_NORM		0x1
>  #define PLL_MODE_DEEP		0x2
>  
> +struct rockchip_clk_pll;
> +struct rockchip_pll_data {
> +	void (*get_params)(struct rockchip_clk_pll *pll,
> +			   struct rockchip_pll_rate_table *rate);
> +	int (*set_params)(struct rockchip_clk_pll *pll,
> +			  const struct rockchip_pll_rate_table *rate);
> +};

I'm not a huge fan of function pointer indirection on top of
function pointer indirection (clk_ops). It would be nice if this
was more flat design and different clk_ops existed for different
PLL types that all used the same rockchip_clk_pll structure. But
I don't care too much because I'm not looking at this code all
the time, so if you like this approach then I'm fine.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From sboyd at codeaurora.org  Fri May  6 15:56:45 2016
From: sboyd at codeaurora.org (Stephen Boyd)
Date: Fri, 6 May 2016 15:56:45 -0700
Subject: [PATCH 0/7] clk: rockchip: cleanup some code duplication
In-Reply-To: <1461849075-8310-1-git-send-email-heiko@sntech.de>
References: <1461849075-8310-1-git-send-email-heiko@sntech.de>
Message-ID: <20160506225645.GG3492@codeaurora.org>

On 04/28, Heiko Stuebner wrote:
> This tries to generalize code paths that contain some (nearly)
> duplicate code. While it's only a bit noticeable now for 3 different
> plls, the effect should be more pronounced when the next pll-type
> shows up.
> 

Looks ok. Are you sending another pull? Or I can apply them
directly.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From heiko at sntech.de  Sun May  8 13:24:37 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sun, 08 May 2016 22:24:37 +0200
Subject: [PATCH 4/7] clk: rockchip: abstract pll get-params and set-params
 operations
In-Reply-To: <20160506225543.GF3492@codeaurora.org>
References: <1461849075-8310-1-git-send-email-heiko@sntech.de>
 <1461849075-8310-5-git-send-email-heiko@sntech.de>
 <20160506225543.GF3492@codeaurora.org>
Message-ID: <3451726.6PKcY6Rd6y@phil>

Am Freitag, 6. Mai 2016, 15:55:43 schrieb Stephen Boyd:
> On 04/28, Heiko Stuebner wrote:
> > This moves the pll-specific get_params and set_params functions into a
> > per-pll struct that gets associated at init time and will help us reign
> > in some code duplication we're faced with right now.
> > 
> > Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> > ---
> > 
> >  drivers/clk/rockchip/clk-pll.c | 54
> >  ++++++++++++++++++++++++++++++++---------- 1 file changed, 42
> >  insertions(+), 12 deletions(-)
> > 
> > diff --git a/drivers/clk/rockchip/clk-pll.c
> > b/drivers/clk/rockchip/clk-pll.c index e56637d..2c30f52 100644
> > --- a/drivers/clk/rockchip/clk-pll.c
> > +++ b/drivers/clk/rockchip/clk-pll.c
> > @@ -30,6 +30,14 @@
> > 
> >  #define PLL_MODE_NORM		0x1
> >  #define PLL_MODE_DEEP		0x2
> > 
> > +struct rockchip_clk_pll;
> > +struct rockchip_pll_data {
> > +	void (*get_params)(struct rockchip_clk_pll *pll,
> > +			   struct rockchip_pll_rate_table *rate);
> > +	int (*set_params)(struct rockchip_clk_pll *pll,
> > +			  const struct rockchip_pll_rate_table *rate);
> > +};
> 
> I'm not a huge fan of function pointer indirection on top of
> function pointer indirection (clk_ops). It would be nice if this
> was more flat design and different clk_ops existed for different
> PLL types that all used the same rockchip_clk_pll structure. But
> I don't care too much because I'm not looking at this code all
> the time, so if you like this approach then I'm fine.

I think the "flat design" is what we have right now. The problem is that the 
core code is pretty similar and only the hardware-specific accesses are 
special, thus the later indirection.

As we don't save to much right now with the currently handled PLLs, I guess 
we could simply only do the first 3 patches and revisit the pll-changes later 
once the next pll-type shows up.


From heiko at sntech.de  Sun May  8 13:34:41 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sun, 08 May 2016 22:34:41 +0200
Subject: [RFC PATCH 2/3] clk: adjust clocks to their requested rate after
 parent changes
In-Reply-To: <CAD=FV=WegPb3AMsUM+Rx_uZ3sMCGUFz-vEh_8WDTqTp1MHWOUQ@mail.gmail.com>
References: <1462206982-10444-1-git-send-email-heiko@sntech.de>
 <CAD=FV=X6at49s-8Wh3+RnLwNQr5RqDMvfJJF+TwvuhnurmQk1w@mail.gmail.com>
 <CAD=FV=WegPb3AMsUM+Rx_uZ3sMCGUFz-vEh_8WDTqTp1MHWOUQ@mail.gmail.com>
Message-ID: <3005442.vcrD3GKCxP@phil>

Am Donnerstag, 5. Mai 2016, 17:49:39 schrieb Doug Anderson:
> Hi,
> 
> On Thu, May 5, 2016 at 5:35 PM, Doug Anderson <dianders at chromium.org> wrote:
> > I guess we don't care about errors here?
> > 
> > ...maybe (?) we could ignore errors if we validated this rate change
> > with PRE_RATE_CHANGE before attempting to change the parent clock, but
> > I don't see the code doing this unless I missed it.
> 
> One other related thought: it seems like there should be code
> _somewhere_ that decides whether to adjust the child dividers before
> or after the parent clock changes.  Specifically if the parent clock
> is increasing in speed we probably want to slow down the child clock
> ahead of the parent's increase.  I don't see such code here, but again
> I'm pretty good at missing things unless they are slapping me in the
> face.  ;)

yep, but that problem of a divider exceeding a requested rate temporarily
exist currently already, even before this change ;-)

Recently we did fix it on a small-scale for composite-clocks though [0].


Heiko


[0] https://git.kernel.org/cgit/linux/kernel/git/clk/linux.git/commit/drivers/clk/clk-composite.c?h=clk-next&id=9e52cec04fd3b9b686f9256151b47fe61f7c28ef



From heiko at sntech.de  Sun May  8 13:51:14 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sun, 08 May 2016 22:51:14 +0200
Subject: [PATCH] clk: rockchip: fix the rk3399 sdmmc sample / drv name
In-Reply-To: <1462404985-27957-1-git-send-email-dianders@chromium.org>
References: <1462404985-27957-1-git-send-email-dianders@chromium.org>
Message-ID: <4645491.pfFL9jxaO2@phil>

Am Mittwoch, 4. Mai 2016, 16:36:25 schrieb Douglas Anderson:
> The rk3399 clock table had a simple typo in it, calling the SDMMC sample
> and drive clocks by the wrong name.  Fix this minor typo.
> 
> Signed-off-by: Douglas Anderson <dianders at chromium.org>

applied to my clk-branch


Thanks for catching this
Heiko


From heiko at sntech.de  Sun May  8 14:22:47 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sun, 08 May 2016 23:22:47 +0200
Subject: [PATCH] ARM: dts: rk3288: add SPI flash node for veyron
In-Reply-To: <1462496564-76530-1-git-send-email-computersforpeace@gmail.com>
References: <1462496564-76530-1-git-send-email-computersforpeace@gmail.com>
Message-ID: <2761761.rShBrpNQKd@phil>

Am Donnerstag, 5. Mai 2016, 18:02:44 schrieb Brian Norris:
> This is a standard binding for describing SPI flash that can be
> identified by reading their JEDEC ID. Let's use it.
> 
> Tested on Veyron Jaq.
> 
> Signed-off-by: Brian Norris <computersforpeace at gmail.com>

I've adapted the subject to
	ARM: dts: rockchip: add SPI flash node for rk3288-veyron

and applied the patch to a temporary dts32-branch for 4.8


Thanks
Heiko




From shawn.lin at rock-chips.com  Sun May  8 20:00:33 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Mon, 9 May 2016 11:00:33 +0800
Subject: [PATCH] mmc: mmc: do not use CMD13 to get status after speed mode
 switch
In-Reply-To: <1462344872-6448-1-git-send-email-chaotian.jing@mediatek.com>
References: <1462344872-6448-1-git-send-email-chaotian.jing@mediatek.com>
Message-ID: <5fa01153-6724-5426-1f71-b7caf31bf796@rock-chips.com>

+ linux-rockchip


I just hacked my local branch to fix the issues found on rockchip
platform. The reaseon is that mmc core fail to get status
after switching from hs200 to hs. So I disabled sending status for it
just like what Chaotian does here. But I didn't deeply dig out the root
cause but I agree with Chaotian's opinion.

FYI:
My emmc deivce is KLMA62WEPD-B031.

[    1.526008] sdhci: Secure Digital Host Controller Interface driver
[    1.526558] sdhci: Copyright(c) Pierre Ossman
[    1.527899] sdhci-pltfm: SDHCI platform and OF driver helper
[    1.529967] sdhci-arasan fe330000.sdhci: No vmmc regulator found
[    1.530501] sdhci-arasan fe330000.sdhci: No vqmmc regulator found
[    1.568710] mmc0: SDHCI controller on fe330000.sdhci [fe330000.sdhci] 
using ADMA
[    1.627552] mmc0: switch to high-speed from hs200 failed, err:-84
[    1.628108] mmc0: error -84 whilst initialising MMC card


? 2016/5/4 14:54, Chaotian Jing ??:
> Per JEDEC spec, it is not recommended to use CMD13 to get card status
> after speed mode switch. below are two reason about this:
> 1. CMD13 cannot be guaranteed due to the asynchronous operation.
> Therefore it is not recommended to use CMD13 to check busy completion
> of the timing change indication.
> 2. After switch to HS200, CMD13 will get response of 0x800, and even the
> busy signal gets de-asserted, the response of CMD13 is aslo 0x800.
>
> this patch drops CMD13 when doing speed mode switch, if host do not
> support MMC_CAP_WAIT_WHILE_BUSY and there is no ops->card_busy(),
> then the only way is to wait a fixed timeout.
>
> Signed-off-by: Chaotian Jing <chaotian.jing at mediatek.com>
> ---
>  drivers/mmc/core/mmc.c     |   82 ++++++++++++++++----------------------------
>  drivers/mmc/core/mmc_ops.c |   25 +++++++++-----
>  2 files changed, 45 insertions(+), 62 deletions(-)
>
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 4dbe3df..03ee7a4 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -962,7 +962,7 @@ static int mmc_select_hs(struct mmc_card *card)
>  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>  			   EXT_CSD_HS_TIMING, EXT_CSD_TIMING_HS,
>  			   card->ext_csd.generic_cmd6_time,
> -			   true, true, true);
> +			   true, false, true);
>  	if (!err)
>  		mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>
> @@ -1056,7 +1056,6 @@ static int mmc_switch_status(struct mmc_card *card)
>  static int mmc_select_hs400(struct mmc_card *card)
>  {
>  	struct mmc_host *host = card->host;
> -	bool send_status = true;
>  	unsigned int max_dtr;
>  	int err = 0;
>  	u8 val;
> @@ -1068,9 +1067,6 @@ static int mmc_select_hs400(struct mmc_card *card)
>  	      host->ios.bus_width == MMC_BUS_WIDTH_8))
>  		return 0;
>
> -	if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
> -		send_status = false;
> -
>  	/* Reduce frequency to HS frequency */
>  	max_dtr = card->ext_csd.hs_max_dtr;
>  	mmc_set_clock(host, max_dtr);
> @@ -1080,7 +1076,7 @@ static int mmc_select_hs400(struct mmc_card *card)
>  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>  			   EXT_CSD_HS_TIMING, val,
>  			   card->ext_csd.generic_cmd6_time,
> -			   true, send_status, true);
> +			   true, false, true);
>  	if (err) {
>  		pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
>  			mmc_hostname(host), err);
> @@ -1090,11 +1086,9 @@ static int mmc_select_hs400(struct mmc_card *card)
>  	/* Set host controller to HS timing */
>  	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>
> -	if (!send_status) {
> -		err = mmc_switch_status(card);
> -		if (err)
> -			goto out_err;
> -	}
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
>
>  	/* Switch card to DDR */
>  	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> @@ -1113,7 +1107,7 @@ static int mmc_select_hs400(struct mmc_card *card)
>  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>  			   EXT_CSD_HS_TIMING, val,
>  			   card->ext_csd.generic_cmd6_time,
> -			   true, send_status, true);
> +			   true, false, true);
>  	if (err) {
>  		pr_err("%s: switch to hs400 failed, err:%d\n",
>  			 mmc_hostname(host), err);
> @@ -1124,11 +1118,9 @@ static int mmc_select_hs400(struct mmc_card *card)
>  	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>  	mmc_set_bus_speed(card);
>
> -	if (!send_status) {
> -		err = mmc_switch_status(card);
> -		if (err)
> -			goto out_err;
> -	}
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
>
>  	return 0;
>
> @@ -1146,14 +1138,10 @@ int mmc_hs200_to_hs400(struct mmc_card *card)
>  int mmc_hs400_to_hs200(struct mmc_card *card)
>  {
>  	struct mmc_host *host = card->host;
> -	bool send_status = true;
>  	unsigned int max_dtr;
>  	int err;
>  	u8 val;
>
> -	if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
> -		send_status = false;
> -
>  	/* Reduce frequency to HS */
>  	max_dtr = card->ext_csd.hs_max_dtr;
>  	mmc_set_clock(host, max_dtr);
> @@ -1162,49 +1150,43 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
>  	val = EXT_CSD_TIMING_HS;
>  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
>  			   val, card->ext_csd.generic_cmd6_time,
> -			   true, send_status, true);
> +			   true, false, true);
>  	if (err)
>  		goto out_err;
>
>  	mmc_set_timing(host, MMC_TIMING_MMC_DDR52);
>
> -	if (!send_status) {
> -		err = mmc_switch_status(card);
> -		if (err)
> -			goto out_err;
> -	}
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
>
>  	/* Switch HS DDR to HS */
>  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_BUS_WIDTH,
>  			   EXT_CSD_BUS_WIDTH_8, card->ext_csd.generic_cmd6_time,
> -			   true, send_status, true);
> +			   true, false, true);
>  	if (err)
>  		goto out_err;
>
>  	mmc_set_timing(host, MMC_TIMING_MMC_HS);
>
> -	if (!send_status) {
> -		err = mmc_switch_status(card);
> -		if (err)
> -			goto out_err;
> -	}
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
>
>  	/* Switch HS to HS200 */
>  	val = EXT_CSD_TIMING_HS200 |
>  	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
>  	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
>  			   val, card->ext_csd.generic_cmd6_time, true,
> -			   send_status, true);
> +			   false, true);
>  	if (err)
>  		goto out_err;
>
>  	mmc_set_timing(host, MMC_TIMING_MMC_HS200);
>
> -	if (!send_status) {
> -		err = mmc_switch_status(card);
> -		if (err)
> -			goto out_err;
> -	}
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
>
>  	mmc_set_bus_speed(card);
>
> @@ -1243,7 +1225,6 @@ static void mmc_select_driver_type(struct mmc_card *card)
>  static int mmc_select_hs200(struct mmc_card *card)
>  {
>  	struct mmc_host *host = card->host;
> -	bool send_status = true;
>  	unsigned int old_timing;
>  	int err = -EINVAL;
>  	u8 val;
> @@ -1260,9 +1241,6 @@ static int mmc_select_hs200(struct mmc_card *card)
>
>  	mmc_select_driver_type(card);
>
> -	if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
> -		send_status = false;
> -
>  	/*
>  	 * Set the bus width(4 or 8) with host's support and
>  	 * switch to HS200 mode if bus width is set successfully.
> @@ -1274,20 +1252,18 @@ static int mmc_select_hs200(struct mmc_card *card)
>  		err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>  				   EXT_CSD_HS_TIMING, val,
>  				   card->ext_csd.generic_cmd6_time,
> -				   true, send_status, true);
> +				   true, false, true);
>  		if (err)
>  			goto err;
>  		old_timing = host->ios.timing;
>  		mmc_set_timing(host, MMC_TIMING_MMC_HS200);
> -		if (!send_status) {
> -			err = mmc_switch_status(card);
> -			/*
> -			 * mmc_select_timing() assumes timing has not changed if
> -			 * it is a switch error.
> -			 */
> -			if (err == -EBADMSG)
> -				mmc_set_timing(host, old_timing);
> -		}
> +		err = mmc_switch_status(card);
> +		/*
> +		 * mmc_select_timing() assumes timing has not changed if
> +		 * it is a switch error.
> +		 */
> +		if (err == -EBADMSG)
> +			mmc_set_timing(host, old_timing);
>  	}
>  err:
>  	if (err)
> diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
> index 62355bd..32de144 100644
> --- a/drivers/mmc/core/mmc_ops.c
> +++ b/drivers/mmc/core/mmc_ops.c
> @@ -480,6 +480,7 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
>  	u32 status = 0;
>  	bool use_r1b_resp = use_busy_signal;
>  	bool expired = false;
> +	bool busy = false;
>
>  	mmc_retune_hold(host);
>
> @@ -535,19 +536,24 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
>  	/* Must check status to be sure of no errors. */
>  	timeout = jiffies + msecs_to_jiffies(timeout_ms);
>  	do {
> +		/*
> +		 * Due to the possibility of being preempted after
> +		 * sending the status command, check the expiration
> +		 * time first.
> +		 */
> +		expired = time_after(jiffies, timeout);
>  		if (send_status) {
> -			/*
> -			 * Due to the possibility of being preempted after
> -			 * sending the status command, check the expiration
> -			 * time first.
> -			 */
> -			expired = time_after(jiffies, timeout);
>  			err = __mmc_send_status(card, &status, ignore_crc);
>  			if (err)
>  				goto out;
>  		}
>  		if ((host->caps & MMC_CAP_WAIT_WHILE_BUSY) && use_r1b_resp)
>  			break;
> +		if (host->ops->card_busy) {
> +			if (!host->ops->card_busy(host))
> +				break;
> +			busy = true;
> +		}
>  		if (mmc_host_is_spi(host))
>  			break;
>
> @@ -556,19 +562,20 @@ int __mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
>  		 * does'nt support MMC_CAP_WAIT_WHILE_BUSY, then we can only
>  		 * rely on waiting for the stated timeout to be sufficient.
>  		 */
> -		if (!send_status) {
> +		if (!send_status && !host->ops->card_busy) {
>  			mmc_delay(timeout_ms);
>  			goto out;
>  		}
>
>  		/* Timeout if the device never leaves the program state. */
> -		if (expired && R1_CURRENT_STATE(status) == R1_STATE_PRG) {
> +		if (expired &&
> +		    (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy)) {
>  			pr_err("%s: Card stuck in programming state! %s\n",
>  				mmc_hostname(host), __func__);
>  			err = -ETIMEDOUT;
>  			goto out;
>  		}
> -	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG);
> +	} while (R1_CURRENT_STATE(status) == R1_STATE_PRG || busy);
>
>  	err = mmc_switch_status_error(host, status);
>  out:
>


-- 
Best Regards
Shawn Lin



From davem at davemloft.net  Sun May  8 20:42:56 2016
From: davem at davemloft.net (David Miller)
Date: Sun, 08 May 2016 23:42:56 -0400 (EDT)
Subject: [PATCH v2] net: arc/emac: Move arc_emac_tx_clean() into
 arc_emac_tx() and disable tx interrut
In-Reply-To: <1462537156-10489-1-git-send-email-wxt@rock-chips.com>
References: <1462537156-10489-1-git-send-email-wxt@rock-chips.com>
Message-ID: <20160508.234256.359620681931531068.davem@davemloft.net>

From: Caesar Wang <wxt at rock-chips.com>
Date: Fri,  6 May 2016 20:19:16 +0800

> Doing tx_clean() inside poll() may scramble the tx ring buffer if
> tx() is running. This will cause tx to stop working, which can be
> reproduced by simultaneously downloading two large files at high speed.
> 
> Moving tx_clean() into tx() will prevent this. And tx interrupt is no
> longer needed now.

TX completion work is always recommended to be done in the ->poll()
handler.

Fix the race or whatever bug there is rather than working around it,
and regressing the driver, by handling TX completion in the interrupt
handler.

Thanks.


From enric.balletbo at collabora.com  Mon May  9 03:46:33 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Mon,  9 May 2016 12:46:33 +0200
Subject: [PATCH v2 3/5] ASoC: rockchip-max98090: Fix jack detection and event
 reporting.
In-Reply-To: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
References: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462790795-25345-4-git-send-email-enric.balletbo@collabora.com>

Physically there is a jackset which includes a Headphone and a Jackset
Mic pin. The patch add thw two pins with the correct pin name so the
DAPM management can find the pin and make the jack detection and event
reporting work again.

The patch also shut up the following error:

 rockchip-snd-max98090 sound: ASoC: DAPM unknown pin Headset Jack

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
---
Changes since v1:
 - Improve log message.
 - Include Headphone and Jackset Mic pins.

 sound/soc/rockchip/rockchip_max98090.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index 3da7891..e70ffad 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -34,13 +34,18 @@
 #define DRV_NAME "rockchip-snd-max98090"
 
 static struct snd_soc_jack headset_jack;
+
+/* Headset jack detection DAPM pins */
 static struct snd_soc_jack_pin headset_jack_pins[] = {
 	{
-		.pin = "Headset Jack",
-		.mask = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
-			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-			SND_JACK_BTN_2 | SND_JACK_BTN_3,
+		.pin = "Headphone",
+		.mask = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin = "Headset Mic",
+		.mask = SND_JACK_MICROPHONE,
 	},
+
 };
 
 static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
-- 
2.1.0



From enric.balletbo at collabora.com  Mon May  9 03:46:35 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Mon,  9 May 2016 12:46:35 +0200
Subject: [PATCH v2 5/5] ARM: dts: rockchip: veyron: Add analog audio codecs.
In-Reply-To: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
References: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462790795-25345-6-git-send-email-enric.balletbo@collabora.com>

Add analog-audio functionality for Veyron devices.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
---
Changes since v1:
 - None

 arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
index 610769d..e25bb1a 100644
--- a/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi
@@ -46,6 +46,7 @@
 #include <dt-bindings/clock/rockchip,rk808.h>
 #include <dt-bindings/input/input.h>
 #include "rk3288-veyron.dtsi"
+#include "rk3288-veyron-analog-audio.dtsi"
 #include "rk3288-veyron-sdmmc.dtsi"
 
 / {
-- 
2.1.0



From enric.balletbo at collabora.com  Mon May  9 03:46:32 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Mon,  9 May 2016 12:46:32 +0200
Subject: [PATCH v2 2/5] ASoC: rockchip-max98090: Fix the Headset Mic route.
In-Reply-To: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
References: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462790795-25345-3-git-send-email-enric.balletbo@collabora.com>

The path Headset Mic --> MICBIAS is wrong because connects a non-supply
widget as a source with a supply widget as a sink. It's the other way
around:

  MICBIAS (source) --> Headset Mic (sink).

This patch also shut up the following error message:

 rockchip-snd-max98090 sound: Connecting non-supply widget to supply widget is not supported (Headset Mic -> MICBIAS)
 rockchip-snd-max98090 sound: ASoC: no dapm match for Headset Mic --> (null) --> MICBIAS
 rockchip-snd-max98090 sound: ASoC: Failed to add route Headset Mic -> direct -> MICBIAS

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
---
Changes since v1:
 - Improve log message.

 sound/soc/rockchip/rockchip_max98090.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index abb64a5..3da7891 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -53,7 +53,7 @@ static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
 static const struct snd_soc_dapm_route rk_audio_map[] = {
 	{"IN34", NULL, "Headset Mic"},
 	{"IN34", NULL, "MICBIAS"},
-	{"MICBIAS", NULL, "Headset Mic"},
+	{"Headset Mic", NULL, "MICBIAS"},
 	{"DMICL", NULL, "Int Mic"},
 	{"Headphone", NULL, "HPL"},
 	{"Headphone", NULL, "HPR"},
-- 
2.1.0



From enric.balletbo at collabora.com  Mon May  9 03:46:34 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Mon,  9 May 2016 12:46:34 +0200
Subject: [PATCH v2 4/5] ARM: dts: rockchip: Add shared file for audio related
 nodes for veyron boards
In-Reply-To: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
References: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462790795-25345-5-git-send-email-enric.balletbo@collabora.com>

Set i2s block to "okay", add sound node for max98090 with gpios for
HP and Mic detect and pinctrl, and add a max98090 device and ts3a227e to
the correct i2c bus.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
---
Changes since v1:
 - None

 arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi | 102 ++++++++++++++++++++++
 1 file changed, 102 insertions(+)
 create mode 100644 arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi

diff --git a/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi b/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
new file mode 100644
index 0000000..f045e1a
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
@@ -0,0 +1,102 @@
+/*
+ * Google Veyron (and derivatives) fragment for the  max98090 audio
+ * codec and analog headphone jack.
+ *
+ * Copyright 2016 Google, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/ {
+
+	sound {
+		compatible = "rockchip,rockchip-audio-max98090";
+		rockchip,model = "ROCKCHIP-I2S";
+		rockchip,i2s-controller = <&i2s>;
+		rockchip,audio-codec = <&max98090>;
+		rockchip,hp-det-gpios = <&gpio6 5 GPIO_ACTIVE_HIGH>;
+		rockchip,mic-det-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
+		rockchip,headset-codec = <&headsetcodec>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&mic_det>, <&hp_det>;
+	};
+
+	io-domains {
+		audio-supply = <&vcc18_codec>;
+	};
+};
+
+&rk808 {
+	vcc10-supply = <&vcc33_sys>;
+
+	regulators {
+		vcc18_codec: LDO_REG6 {
+			regulator-always-on;
+			regulator-boot-on;
+			regulator-min-microvolt = <1800000>;
+			regulator-max-microvolt = <1800000>;
+			regulator-name = "vcc18_codec";
+			regulator-suspend-mem-disabled;
+		};
+	};
+};
+
+&i2c2 {
+	max98090: max98090 at 10 {
+		compatible = "maxim,max98090";
+		reg = <0x10>;
+		clock-names = "mclk";
+		clocks = <&cru SCLK_I2S0_OUT>;
+		interrupt-parent = <&gpio6>;
+		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&int_codec>;
+	};
+};
+
+&i2c4 {
+	headsetcodec: ts3a227e at 3b {
+		compatible = "ti,ts3a227e";
+		reg = <0x3b>;
+		interrupt-parent = <&gpio0>;
+		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&ts3a227e_int_l>;
+		ti,micbias = <7>;		/* MICBIAS = 2.8V */
+	};
+};
+
+&i2s {
+	status = "okay";
+	clock-names = "i2s_hclk", "i2s_clk";
+	clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+};
+
+&pinctrl {
+	codec {
+		hp_det: hp-det {
+			rockchip,pins = <6 5 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+
+		/*
+		 * HACK: We're going to _pull down_ this _active low_ interrupt
+		 * so that it never fires.  We don't need this interrupt because
+		 * we've got a ts3a227e chip but the driver requires it.
+		 */
+		int_codec: int-codec {
+			rockchip,pins = <6 7 RK_FUNC_GPIO &pcfg_pull_down>;
+		};
+
+		mic_det: mic-det {
+			rockchip,pins = <6 11 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+
+	headset {
+		ts3a227e_int_l: ts3a227e-int-l {
+			rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_up>;
+		};
+	};
+};
-- 
2.1.0



From enric.balletbo at collabora.com  Mon May  9 03:46:31 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Mon,  9 May 2016 12:46:31 +0200
Subject: [PATCH v2 1/5] ASoC: rockchip-max98090: Fix NULL pointer dereference
 while accessing to jack.
In-Reply-To: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
References: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1462790795-25345-2-git-send-email-enric.balletbo@collabora.com>

Commit f2ed6b07645e ("ASoC: Make aux_dev more like a generic
component") caused a regression on this driver, since now a
kernel oops is seen when rockchip-mac98090 driver is loaded.

That commit changed the probing of aux_devs before checking
new DAI links, so for this driver rk_98090_headset_init is
called before rk_init and then the kernel oops due a NULL
pointer dereference inside rk_98090_headset_init function
since there is a call that tries to access the jack pointer
which has not been allocated yet.

This is the call chain that causes the crash:

 rk_98090_headset_init
   -> ts3a227e_enable_jack_detect
      -> snd_jack_set_key
 rk_init
   -> snd_soc_card_jack_new

This patch moves the new jack object creation from rk_init
to rk_98090_headset_init function making sure the jack is
created before is accessed.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
---
Changes since v1:
 - Improve log message.

 sound/soc/rockchip/rockchip_max98090.c | 50 ++++++++++++++++++----------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index 5436102..abb64a5 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -114,43 +114,27 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static int rk_init(struct snd_soc_pcm_runtime *runtime)
-{
-	/* Enable Headset and 4 Buttons Jack detection */
-	return snd_soc_card_jack_new(runtime->card, "Headset Jack",
-			       SND_JACK_HEADSET |
-			       SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-			       SND_JACK_BTN_2 | SND_JACK_BTN_3,
-			       &headset_jack,
-			       headset_jack_pins,
-			       ARRAY_SIZE(headset_jack_pins));
-}
-
-static int rk_98090_headset_init(struct snd_soc_component *component)
-{
-	return ts3a227e_enable_jack_detect(component, &headset_jack);
-}
-
 static struct snd_soc_ops rk_aif1_ops = {
 	.hw_params = rk_aif1_hw_params,
 };
 
-static struct snd_soc_aux_dev rk_98090_headset_dev = {
-	.name = "Headset Chip",
-	.init = rk_98090_headset_init,
-};
-
 static struct snd_soc_dai_link rk_dailink = {
 	.name = "max98090",
 	.stream_name = "Audio",
 	.codec_dai_name = "HiFi",
-	.init = rk_init,
 	.ops = &rk_aif1_ops,
 	/* set max98090 as slave */
 	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 		SND_SOC_DAIFMT_CBS_CFS,
 };
 
+static int rk_98090_headset_init(struct snd_soc_component *component);
+
+static struct snd_soc_aux_dev rk_98090_headset_dev = {
+	.name = "Headset Chip",
+	.init = rk_98090_headset_init,
+};
+
 static struct snd_soc_card snd_soc_card_rk = {
 	.name = "ROCKCHIP-I2S",
 	.owner = THIS_MODULE,
@@ -166,6 +150,26 @@ static struct snd_soc_card snd_soc_card_rk = {
 	.num_controls = ARRAY_SIZE(rk_mc_controls),
 };
 
+static int rk_98090_headset_init(struct snd_soc_component *component)
+{
+	int ret;
+
+	/* Enable Headset and 4 Buttons Jack detection */
+	ret = snd_soc_card_jack_new(&snd_soc_card_rk, "Headset Jack",
+				    SND_JACK_HEADSET |
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
+				    &headset_jack,
+				    headset_jack_pins,
+				    ARRAY_SIZE(headset_jack_pins));
+	if (ret)
+		return ret;
+
+	ret = ts3a227e_enable_jack_detect(component, &headset_jack);
+
+	return ret;
+}
+
 static int snd_rk_mc_probe(struct platform_device *pdev)
 {
 	int ret = 0;
-- 
2.1.0



From enric.balletbo at collabora.com  Mon May  9 03:46:30 2016
From: enric.balletbo at collabora.com (Enric Balletbo i Serra)
Date: Mon,  9 May 2016 12:46:30 +0200
Subject: [PATCH v2 0/5] ASoC: rockchip: Fix audio on Veyron.
Message-ID: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>

Hi all,

This patch series adds support and fixes the audio support for Veyron
devices. With these patches I'm able to playback from speakers and
headphones, and record from the microphone on a Veyron Jerry Chromebook.

Patches from 1/5 to 3/5 should go through the Mark Brown ASoC tree.

Patches 4/5 and 5/5 should go through the Heiko Stuebner rockchip tree.

Changes since v1:
 - Improve log messages trying to explain better the issues (suggested by Mark Brown)
 - Remove patches from John Keeping as are already cherry-picked.
   - https://git.kernel.org/cgit/linux/kernel/git/broonie/sound.git/commit/?h=for-next&id=a6e806c49e3265494ac6fe6ec88ed5c010652e0d
   - https://git.kernel.org/cgit/linux/kernel/git/broonie/sound.git/commit/?h=for-next&id=7e885d211f023dfd201fad8246bbf3c3bd126c61

Enric Balletbo i Serra (5):
  ASoC: rockchip-max98090: Fix NULL pointer dereference while accessing
    to jack.
  ASoC: rockchip-max98090: Fix the Headset Mic route.
  ASoC: rockchip-max98090: Fix jack detection and event reporting.
  ARM: dts: rockchip: Add shared file for audio related nodes for veyron
    boards
  ARM: dts: rockchip: veyron: Add analog audio codecs.

 arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi | 102 ++++++++++++++++++++++
 arch/arm/boot/dts/rk3288-veyron-chromebook.dtsi   |   1 +
 sound/soc/rockchip/rockchip_max98090.c            |  65 ++++++++------
 3 files changed, 140 insertions(+), 28 deletions(-)
 create mode 100644 arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi

-- 
2.1.0



From shawn.lin at rock-chips.com  Mon May  9 04:12:17 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Mon, 9 May 2016 19:12:17 +0800
Subject: [PATCH 2/2] dt-bindings: rockchip-dw-mshc: add
 rockchip,default-drv-phase
In-Reply-To: <CAD=FV=WSkBwBjVsRoDsfjD+sNfR70mKGRA0khjPKKW0zS2=PTw@mail.gmail.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
 <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=WSkBwBjVsRoDsfjD+sNfR70mKGRA0khjPKKW0zS2=PTw@mail.gmail.com>
Message-ID: <b15dcb4f-1584-8219-2fe0-97eecb0c64a6@rock-chips.com>

On 2016/5/7 1:26, Doug Anderson wrote:
> Shawn,
>
> On Fri, May 6, 2016 at 2:41 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> rockchip,default-drv-phase is used to set the default drv degrees.
>> drv phases will decide the write timing of mmc controller.
>
> Device tree bindings should probably have been patch 1/2, then the
> code patch 2/2.
>
>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> ---
>>
>>  Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt | 3 +++
>>  1 file changed, 3 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
>> index ea5614b..c48dba6 100644
>> --- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
>> +++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
>> @@ -29,6 +29,9 @@ Optional Properties:
>>    probing, low speeds or in case where all phases work at tuning time.
>>    If not specified 0 deg will be used.
>>
>> +* rockchip,default-drv-phase: The default phase to set ciu_drv at probing
>> +  for host to write data to devices. If not specified 180 deg will be used.
>
> This is probably not right for a few reasons.
>
> 1. Specifying a single number for this property in terms of "degrees"
> is probably not right.  The whole point of setting the "drive phase"
> is to meet hold times, which are specified in the spec in terms of ns
> in the spec and also specified differently for different SD/MMC speed
> modes.  Note also that "phase" translates to very different delays (in
> terms of ns) depending on the clock rate:
>
> At 400 kHz, period is 2.5 us, so 90 degree phase offset is a delay of 625 ns
> At 25 MHz, period is 40 ns, so a 90 degree phase offset represents a
> delay of 10 ns.
> At 50 MHz, period is 20 ns, so a 90 degree phase offset represents a
> delay of 5 ns.
> At 200 MHz, period is period is 5 ns, so a 90 degree phase offset
> represents a delay of 1.25 ns.

yes, if we use degrees only(0/90/180/270), the timing is always right.
But considering the delay number, we need to do some crazy calculation
in the set_ios callback.

>
>
> 2. As I understand it, the value needed for the drive phase is not
> board specific unless you've got super crazy layout on a board (where
> the clock line takes a very different path than everything else).
> It's also not even terribly SoC-specific unless you've got some very
> strange incarnation of dw_mmc that has very different internal delays
> than everyone else.  Said another way, until we see an instance of an
> SoC/board that really needs to do things special I'd say that we
> should just implement this all in code (no device tree bindings).
>

I'm prone to think it should be Soc specific if making sure the layout
for data lines is in equal length.

>
>
> 3. If this property was actually board specific and actually needed to
> be tuned board-by-board, you'd have a bug because your new device tree
> bindings are not backward compatible and you'd probably be breaking
> old boards.  Specifically you're changing the definition of what
> happens when "rockchip,default-drv-phase" is not specified.  Old
> behavior was to leave the value that was setup by the firmware (or
> perhaps the hardware default if the firmware didn't touch this).

drv_phase is for all the data lines instead of tuning the lines
one-by-one. So this patch can't save the terrible board layout.
But I agree that it will break the compatibility backward if firware
touch this value.

>
> ---
>
> OK, so what should we do?
>
> We could certainly do lots of crazy math to come up with the ideal
> hold time for all different speed modes and all different types of
> cards.  With my reading of the Designware Databook this would mean
> that somewhere we'd want to specify which delay method we're using
> (phase shift vs. delay line) and how long all the delays timings all
> are on your particular SoC.  That all sounds quite difficult, though.

delay line is diff from chip to chip, soc-to-soc, board-to-board. For 
sample-phase we have tuning process and re-tune, but not for drv-phase.
So We bascially should avoid to use it for drv-phase. Another
consideration is the temperature drift of delay line.

Maybe we should do some tricky limitation on clk-mmc-phase to only
support fixed degrees?

>
> Probably you could just add a simple function that looked at the clock
> and speed mode and always chose an offset of 90 or 180 degrees.  At
> least on Rockchip devices you can be certain that you can make 90 and
> 180 degrees using phase shifts and thus the timings should be
> consistent.  By default you could just always choose 180.  The
> Designware databook has some examples where it picked 90 degrees
> (SDR50, DDR50, SDR25, MMC High Speed), but I'm not enough of an MMC
> expert to know if there is some benefit to choosing 90.  Would we
> violate any specs if we just chose 180 degrees all the time everywhere
> on all Rockchip devices?

It needs more waveform test to see how things going. But most of
rockchip platforms in the pass years didn't touch drv-phase stuff not
only in kernel but also in firmware, then we still cannot see the
violation against the spec when using defalut reset value, namely 180, 
for drv-phase.

>
>
>
> -Doug
>
>
>


-- 
Best Regards
Shawn Lin



From heiko at sntech.de  Mon May  9 04:40:27 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 09 May 2016 13:40:27 +0200
Subject: [RFC PATCH 2/3] clk: adjust clocks to their requested rate after
 parent changes
In-Reply-To: <CAD=FV=X6at49s-8Wh3+RnLwNQr5RqDMvfJJF+TwvuhnurmQk1w@mail.gmail.com>
References: <1462206982-10444-1-git-send-email-heiko@sntech.de>
 <1462206982-10444-3-git-send-email-heiko@sntech.de>
 <CAD=FV=X6at49s-8Wh3+RnLwNQr5RqDMvfJJF+TwvuhnurmQk1w@mail.gmail.com>
Message-ID: <2927458.4ozSLghtXU@phil>

Am Donnerstag, 5. Mai 2016, 17:35:03 schrieb Doug Anderson:
> Heiko,
> 
> On Mon, May 2, 2016 at 9:36 AM, Heiko Stuebner <heiko at sntech.de> wrote:
> > Given a hirarchy of clk1 -> [div] -> clk2, when the rate of clk1 gets
> > changed, clk2 changes as well as the divider stays the same. There may
> > be cases where a user of clk2 needs it at a specific rate, so clk2
> > needs to be readjusted for the changed rate of clk1.
> > 
> > So if a rate was requested for the clock, and its rate changed during
> > the underlying rate-change, with this change the clock framework now
> > tries to readjust the rate back to/near the requested one.
> > 
> > The whole process is protected by a new clock-flag to not force this
> > behaviour change onto every clock defined in the ccf.
> 
> I'm not an expert on CCF details, but presumably you need to be really
> careful here.  Is there any way you could get an infinite loop here
> where you ping-pong between two people trying to control their parent
> clock?  Right now I see mutual recursion between
> clk_core_set_rate_nolock() and clk_change_rate() and no base case.
> 
> Specifically if there's a path (because of CLK_SET_RATE_PARENT) where
> setting a clock rate on "clk2" in your example can cause a rate change
> of "clk1" I worry that we'll be in trouble.  Maybe a requirement of
> your patch is that no such path exists?  ...or maybe something in the
> code prevents this...

This was one of my worries as well, which is why the flag exists in the first 
place, right now offloading the requirement to check for such conflict cases to 
the clock-tree creator.


I think one possible test to add could be to check for conflicts between 
CLK_SET_RATE_PARENT and this new flag.

Aka in clk-init once encountering the CLK_KEEP_REQRATE, go up through parent 
clocks as long as CLK_SET_RATE_PARENT is set and if we encounter a parent 
with num_children > 1 (aka a shared base-clock, like a PLL on rockchip) 
unset CLK_KEEP_REQRATE, as it would like introduce that ping-pong game.

Hmm, although this test would also fire in cases like Rockchip's fractional 
dividers, where there is the common pll-select-mux+divider and after that 
the mux selecting between that or having the fractional-divider in between 
as well.

I guess it can get hairy to detect such cases sucessfully.


> > Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> > ---
> > 
> >  drivers/clk/clk.c            | 13 +++++++++++--
> >  include/linux/clk-provider.h |  1 +
> >  2 files changed, 12 insertions(+), 2 deletions(-)
> > 
> > diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
> > index 65e0aad..22be369 100644
> > --- a/drivers/clk/clk.c
> > +++ b/drivers/clk/clk.c
> > @@ -1410,6 +1410,9 @@ static struct clk_core
> > *clk_propagate_rate_change(struct clk_core *core,> 
> >         return fail_clk;
> >  
> >  }
> > 
> > +static int clk_core_set_rate_nolock(struct clk_core *core,
> > +                                   unsigned long req_rate);
> > +
> > 
> >  /*
> >  
> >   * walk down a subtree and set the new rates notifying the rate
> >   * change on the way
> > 
> > @@ -1494,6 +1497,12 @@ static void clk_change_rate(struct clk_core
> > *core)
> > 
> >         /* handle the new child who might not be in core->children yet
> >         */
> >         if (core->new_child)
> >         
> >                 clk_change_rate(core->new_child);
> > 
> > +
> > +       /* handle a changed clock that needs to readjust its rate */
> > +       if (core->flags & CLK_KEEP_REQ_RATE && core->req_rate
> > +                                           && core->new_rate !=
> > old_rate
> > +                                           && core->new_rate !=
> > core->req_rate) +               clk_core_set_rate_nolock(core,
> > core->req_rate);
> 
> I guess we don't care about errors here?
> 
> ...maybe (?) we could ignore errors if we validated this rate change
> with PRE_RATE_CHANGE before attempting to change the parent clock, but
> I don't see the code doing this unless I missed it.

It's more like what would you want to do in the error/failure cases.

So far I was going by the assumption we're going to change the clock anyway 
and just try to pull marked clocks along, so in the error case it would just 
fall back to the current behaviour.


Heiko

> >  }
> >  
> >  static int clk_core_set_rate_nolock(struct clk_core *core,
> > 
> > @@ -1529,11 +1538,11 @@ static int clk_core_set_rate_nolock(struct
> > clk_core *core,> 
> >                 return -EBUSY;
> >         
> >         }
> > 
> > +       core->req_rate = req_rate;
> > +
> > 
> >         /* change the rates */
> >         clk_change_rate(top);
> > 
> > -       core->req_rate = req_rate;
> > -
> > 
> >         return ret;
> >  
> >  }
> > 
> > diff --git a/include/linux/clk-provider.h b/include/linux/clk-provider.h
> > index 0c72204..06f189e 100644
> > --- a/include/linux/clk-provider.h
> > +++ b/include/linux/clk-provider.h
> > @@ -33,6 +33,7 @@
> > 
> >  #define CLK_RECALC_NEW_RATES   BIT(9) /* recalc rates after
> >  notifications */ #define CLK_SET_RATE_UNGATE    BIT(10) /* clock needs
> >  to run to set rate */ #define CLK_IS_CRITICAL                BIT(11)
> >  /* do not gate, ever */> 
> > +#define CLK_KEEP_REQ_RATE      BIT(12) /* keep reqrate on parent rate
> > change */
> s/reqrate/req_rate/



From adrian.hunter at intel.com  Mon May  9 04:56:38 2016
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Mon, 9 May 2016 14:56:38 +0300
Subject: [PATCH v2 3/6] mmc: core: implement enhanced strobe support
In-Reply-To: <1461898029-28944-1-git-send-email-shawn.lin@rock-chips.com>
References: <1461897751-28810-1-git-send-email-shawn.lin@rock-chips.com>
 <1461898029-28944-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <57307AF6.8030401@intel.com>

On 29/04/16 05:47, Shawn Lin wrote:
> Controllers use data strobe line to latch data from devices
> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
> introduces enhanced strobe mode for latching cmd response from
> emmc devices to host controllers. This new feature is optional,
> so it depends both on device's cap and host's cap to decide
> whether to use it or not.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

Thanks for doing this.  There are a couple of comments below, but generally
I tend to think you should split out selecting HS400ES as a separate function.

> ---
> 
> Changes in v2: None
> 
>  drivers/mmc/core/bus.c   |  3 +-
>  drivers/mmc/core/mmc.c   | 77 ++++++++++++++++++++++++++++++++++++++++++++----
>  include/linux/mmc/card.h |  1 +
>  include/linux/mmc/host.h | 12 ++++++++
>  include/linux/mmc/mmc.h  |  3 ++
>  5 files changed, 89 insertions(+), 7 deletions(-)
> 
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index 4bc48f1..7e94b9d 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			type);
>  	} else {
> -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>  			mmc_hostname(card->host),
>  			mmc_card_uhs(card) ? "ultra high speed " :
>  			(mmc_card_hs(card) ? "high speed " : ""),
>  			mmc_card_hs400(card) ? "HS400 " :
>  			(mmc_card_hs200(card) ? "HS200 " : ""),
> +			mmc_card_hs400es(card) ? "Enhanced strobe" : "",
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			uhs_bus_speed_mode, type, card->rca);
>  	}
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index 28b477d..f45ed10 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -235,6 +235,12 @@ static void mmc_select_card_type(struct mmc_card *card)
>  		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>  	}
>  
> +	if ((caps2 & MMC_CAP2_HS400_ENHANCED_STROBE) &&
> +	    card->ext_csd.strobe_support &&
> +	    ((card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) ||
> +	     (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)))

Could use just "card_type & EXT_CSD_CARD_TYPE_HS400" here

> +		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
> +
>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>  	card->mmc_avail_type = avail_type;
> @@ -383,6 +389,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>  			mmc_card_set_blockaddr(card);
>  	}
>  
> +	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>  	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>  	mmc_select_card_type(card);
>  
> @@ -1062,9 +1069,10 @@ static int mmc_select_hs400(struct mmc_card *card)
>  	u8 val;
>  
>  	/*
> -	 * HS400 mode requires 8-bit bus width
> +	 * HS400(ES) mode requires 8-bit bus width
>  	 */
> -	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
> +	if (!(((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400) ||
> +		(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)) &&
>  	      host->ios.bus_width == MMC_BUS_WIDTH_8))
>  		return 0;
>  
> @@ -1097,9 +1105,26 @@ static int mmc_select_hs400(struct mmc_card *card)
>  	}
>  
>  	/* Switch card to DDR */
> +	val = EXT_CSD_DDR_BUS_WIDTH_8;
> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
> +		val |= EXT_CSD_BUS_WIDTH_STROBE;
> +		/*
> +		* Make sure we are in non-enhanced strobe mode before we
> +		* actually enable it in ext_csd.
> +		*/
> +		if (host->ops->prepare_enhanced_strobe)
> +			err = host->ops->prepare_enhanced_strobe(host, false);
> +
> +		if (err) {
> +			pr_err("%s: unprepare_enhanced strobe failed, err:%d\n",
> +				mmc_hostname(host), err);
> +			return err;
> +		}
> +	}
> +
>  	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>  			 EXT_CSD_BUS_WIDTH,
> -			 EXT_CSD_DDR_BUS_WIDTH_8,
> +			 val,
>  			 card->ext_csd.generic_cmd6_time);
>  	if (err) {
>  		pr_err("%s: switch to bus width for hs400 failed, err:%d\n",
> @@ -1124,6 +1149,35 @@ static int mmc_select_hs400(struct mmc_card *card)
>  	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>  	mmc_set_bus_speed(card);
>  
> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
> +		/* Controller enable enhanced strobe function */
> +		if (host->ops->prepare_enhanced_strobe)
> +			err = host->ops->prepare_enhanced_strobe(host, true);
> +
> +		if (err) {
> +			pr_err("%s: prepare enhanced strobe failed, err:%d\n",
> +				mmc_hostname(host), err);
> +			return err;
> +		}
> +
> +		/*
> +		 * After switching to hs400 enhanced strobe mode, we expect to
> +		 * verify whether it works or not. If controller can't handle
> +		 * bus width test, compare ext_csd previously read in 1 bit mode
> +		 * against ext_csd at new bus width
> +		 */

I don't think we need this.  Just checking (host->caps & MMC_CAP_8_BIT_DATA)
ought to be enough.  But if you want to play if safe, you could use
mmc_select_bus_width() in advance.

> +		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
> +			err = mmc_compare_ext_csds(card, MMC_BUS_WIDTH_8);
> +		else
> +			err = mmc_bus_test(card, MMC_BUS_WIDTH_8);
> +
> +		if (err) {
> +			pr_warn("%s: switch to enhanced strobe failed\n",
> +				mmc_hostname(host));
> +			return err;
> +		}
> +	}
> +
>  	if (!send_status) {
>  		err = mmc_switch_status(card);
>  		if (err)
> @@ -1297,7 +1351,8 @@ err:
>  }
>  
>  /*
> - * Activate High Speed or HS200 mode if supported.
> + * Activate High Speed or HS200 mode if supported. For HS400
> + * with enhanced strobe mode, we should activate High Speed.
>   */
>  static int mmc_select_timing(struct mmc_card *card)
>  {
> @@ -1306,7 +1361,9 @@ static int mmc_select_timing(struct mmc_card *card)
>  	if (!mmc_can_ext_csd(card))
>  		goto bus_speed;
>  
> -	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
> +		err = mmc_select_hs(card);

In my view, you should just make a new function: mmc_select_hs400es()

> +	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>  		err = mmc_select_hs200(card);
>  	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>  		err = mmc_select_hs(card);
> @@ -1578,7 +1635,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>  	} else if (mmc_card_hs(card)) {
>  		/* Select the desired bus width optionally */
>  		err = mmc_select_bus_width(card);
> -		if (!IS_ERR_VALUE(err)) {
> +		if (IS_ERR_VALUE(err))
> +			goto free_card;
> +
> +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
> +			/* Directly from HS to HS400-ES */
> +			err = mmc_select_hs400(card);
> +			if (err)
> +				goto free_card;
> +		} else {
>  			err = mmc_select_hs_ddr(card);
>  			if (err)
>  				goto free_card;
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index eb0151b..22defc2 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>  	u8			raw_partition_support;	/* 160 */
>  	u8			raw_rpmb_size_mult;	/* 168 */
>  	u8			raw_erased_mem_count;	/* 181 */
> +	u8			strobe_support;		/* 184 */
>  	u8			raw_ext_csd_structure;	/* 194 */
>  	u8			raw_card_type;		/* 196 */
>  	u8			raw_driver_strength;	/* 197 */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 11e89d3..19de56c 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -19,6 +19,7 @@
>  
>  #include <linux/mmc/core.h>
>  #include <linux/mmc/card.h>
> +#include <linux/mmc/mmc.h>
>  #include <linux/mmc/pm.h>
>  
>  struct mmc_ios {
> @@ -143,6 +144,8 @@ struct mmc_host_ops {
>  
>  	/* Prepare HS400 target operating frequency depending host driver */
>  	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
> +	/* Prepare enhanced strobe depending host driver */
> +	int	(*prepare_enhanced_strobe)(struct mmc_host *host, bool enable);

I don't see any need for an error return, so maybe make this return void.
Also, we could put "bool enhanced_strobe" in struct mmc_ios and pass ios
instead of enable.

>  	int	(*select_drive_strength)(struct mmc_card *card,
>  					 unsigned int max_dtr, int host_drv,
>  					 int card_drv, int *drv_type);
> @@ -518,6 +521,15 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>  	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>  }
>  
> +static inline bool mmc_card_hs400es(struct mmc_card *card)
> +{
> +	if (mmc_card_hs400(card) &&
> +	    (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES))
> +		return 1;

We shouldn't assume that we are using it, just because it is available.
How about putting "bool enhanced_strobe" in struct mmc_ios and checking that.

> +
> +	return 0;
> +}
> +
>  void mmc_retune_timer_stop(struct mmc_host *host);
>  
>  static inline void mmc_retune_needed(struct mmc_host *host)
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 15f2c4a..c376209 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -297,6 +297,7 @@ struct _mmc_csd {
>  #define EXT_CSD_PART_CONFIG		179	/* R/W */
>  #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
>  #define EXT_CSD_BUS_WIDTH		183	/* R/W */
> +#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
>  #define EXT_CSD_HS_TIMING		185	/* R/W */
>  #define EXT_CSD_POWER_CLASS		187	/* R/W */
>  #define EXT_CSD_REV			192	/* RO */
> @@ -380,12 +381,14 @@ struct _mmc_csd {
>  #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
>  #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
>  					 EXT_CSD_CARD_TYPE_HS400_1_2V)
> +#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
>  
>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
>  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
>  
>  #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
>  #define EXT_CSD_TIMING_HS	1	/* High speed */
> 



From adrian.hunter at intel.com  Mon May  9 05:00:05 2016
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Mon, 9 May 2016 15:00:05 +0300
Subject: [PATCH v2 4/6] mmc: debugfs: add HS400 enhanced strobe description
In-Reply-To: <1461898092-28985-1-git-send-email-shawn.lin@rock-chips.com>
References: <1461897751-28810-1-git-send-email-shawn.lin@rock-chips.com>
 <1461898092-28985-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <57307BC5.50301@intel.com>

On 29/04/16 05:48, Shawn Lin wrote:
> We inctroduce HS400 with enhanced strobe function, so we need

inctroduce -> introduced

> add it for debug show.

add -> to add

> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
> 
> Changes in v2: None
> 
>  drivers/mmc/core/debugfs.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 9382a57..51d7c38 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -148,7 +148,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>  		str = "mmc HS200";
>  		break;
>  	case MMC_TIMING_MMC_HS400:
> -		str = "mmc HS400";
> +		mmc_card_hs400es(host->card) ?
> +			(str = "mmc HS400 enhanced strobe") :
> +			(str = "mmc HS400");
>  		break;
>  	default:
>  		str = "invalid";
> 



From adrian.hunter at intel.com  Mon May  9 05:02:19 2016
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Mon, 9 May 2016 15:02:19 +0300
Subject: [PATCH v2 5/6] mmc: sdhci: implement enhanced strobe callback
In-Reply-To: <1461898103-29026-1-git-send-email-shawn.lin@rock-chips.com>
References: <1461897751-28810-1-git-send-email-shawn.lin@rock-chips.com>
 <1461898103-29026-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <57307C4B.2040003@intel.com>

On 29/04/16 05:48, Shawn Lin wrote:
> Enhanced strobe stuff currently is beyond the scope
> of Secure Digital Host Controller Interface. So we can't
> find a register here to enable/disable it. We experct
> variant drivers to finish the details according to their
> vendor settings.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
> 
> Changes in v2: None
> 
>  drivers/mmc/host/sdhci.c | 11 +++++++++++
>  1 file changed, 11 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
> index 94cffa7..a04e4c4 100644
> --- a/drivers/mmc/host/sdhci.c
> +++ b/drivers/mmc/host/sdhci.c
> @@ -2049,6 +2049,16 @@ out_unlock:
>  	return err;
>  }
>  
> +static int sdhci_prepare_enhanced_strobe(struct mmc_host *mmc, bool enable)
> +{
> +	/*
> +	* Currently we can't find a register to enable enhanced strobe
> +	* function for standard sdhci, so we expect variant drivers to
> +	* overwrite it.
> +	*/
> +	return -EINVAL;
> +}

Since we don't need it at the moment, let's not have it at all for now.

> +
>  static int sdhci_select_drive_strength(struct mmc_card *card,
>  				       unsigned int max_dtr, int host_drv,
>  				       int card_drv, int *drv_type)
> @@ -2158,6 +2168,7 @@ static const struct mmc_host_ops sdhci_ops = {
>  	.enable_sdio_irq = sdhci_enable_sdio_irq,
>  	.start_signal_voltage_switch	= sdhci_start_signal_voltage_switch,
>  	.prepare_hs400_tuning		= sdhci_prepare_hs400_tuning,
> +	.prepare_enhanced_strobe	= sdhci_prepare_enhanced_strobe,
>  	.execute_tuning			= sdhci_execute_tuning,
>  	.select_drive_strength		= sdhci_select_drive_strength,
>  	.card_event			= sdhci_card_event,
> 



From arnd at arndb.de  Mon May  9 07:17:43 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Mon, 09 May 2016 16:17:43 +0200
Subject: [GIT PULL 1/3] Rockchip driver updates for v4.7 - part2
In-Reply-To: <2744609.Je9E5Knv0x@diego>
References: <5544434.9tA8JHBIkp@diego> <2744609.Je9E5Knv0x@diego>
Message-ID: <7857890.rMVEHqflgb@wuerfel>

On Friday 29 April 2016 00:24:10 Heiko St?bner wrote:
> Ability to save and restore the power-domain quality of service
> settings that get lost and reset on power-domain power cycles.
> 
> 

Pulled into next/drivers, thanks!

	Arnd


From heiko at sntech.de  Mon May  9 07:22:24 2016
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Mon, 09 May 2016 16:22:24 +0200
Subject: [GIT PULL] rockchip clock changes for 4.7 part 4 - some more fixes
Message-ID: <16076636.fp1YCeqDWQ@phil>

Hi Mike, Stephen,

A fixup for a rk3399 clock name as well as the GRF-portions of
my cleanup series. As Stephen had some mild reservations about the
introduced indirection in the pll parts and we don't save to much lines
with my modifications for the currently supported pll-types, I think it's
easier to postpone those until the next new pll type comes around.

Maybe it even has some completely different properties to handle where
the current "simplification" might even be counter-productive :-) .

So please pull if possible.

Thanks
Heiko


The following changes since commit fd8bc829336a24b770247eb893111bcb8f1ddedb:

  clk: rockchip: fix the rk3399 cifout clock (2016-04-25 22:54:51 +0200)

are available in the git repository at:

  git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v4.7-rockchip-clk4

for you to fetch changes up to 7e5385dc722258c862f969ab7e67907156ad0e3f:

  clk: rockchip: drop old_rate calculation on pll rate changes (2016-05-09 16:04:39 +0200)

----------------------------------------------------------------
Another small rk3399 fixup as well as simplifications around
our handling of the General-Register-Files syscon.

----------------------------------------------------------------
Douglas Anderson (1):
      clk: rockchip: fix the rk3399 sdmmc sample / drv name

Heiko Stuebner (3):
      clk: rockchip: lookup General Register Files in rockchip_clk_init
      clk: rockchip: simplify GRF handling in pll clocks
      clk: rockchip: drop old_rate calculation on pll rate changes

 drivers/clk/rockchip/clk-pll.c    | 45 ++++++++-------------------------------
 drivers/clk/rockchip/clk-rk3399.c |  4 ++--
 drivers/clk/rockchip/clk.c        | 11 +++-------
 drivers/clk/rockchip/clk.h        |  1 -
 4 files changed, 14 insertions(+), 47 deletions(-)



From heiko at sntech.de  Mon May  9 07:28:16 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 09 May 2016 16:28:16 +0200
Subject: [PATCH 0/7] clk: rockchip: cleanup some code duplication
In-Reply-To: <20160506225645.GG3492@codeaurora.org>
References: <1461849075-8310-1-git-send-email-heiko@sntech.de>
 <20160506225645.GG3492@codeaurora.org>
Message-ID: <1846515.jCoz32uTXP@phil>

Am Freitag, 6. Mai 2016, 15:56:45 schrieb Stephen Boyd:
> On 04/28, Heiko Stuebner wrote:
> > This tries to generalize code paths that contain some (nearly)
> > duplicate code. While it's only a bit noticeable now for 3 different
> > plls, the effect should be more pronounced when the next pll-type
> > shows up.
> 
> Looks ok. Are you sending another pull? Or I can apply them
> directly.

I've sent a pull request with the first 3 patches of the series - see comment 
to your doubts to patch 4 and further. Also including one other fix from Doug 
as well).


Heiko


From dianders at chromium.org  Mon May  9 08:49:43 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 9 May 2016 08:49:43 -0700
Subject: [RFC PATCH 2/3] clk: adjust clocks to their requested rate after
 parent changes
In-Reply-To: <2927458.4ozSLghtXU@phil>
References: <1462206982-10444-1-git-send-email-heiko@sntech.de>
 <1462206982-10444-3-git-send-email-heiko@sntech.de>
 <CAD=FV=X6at49s-8Wh3+RnLwNQr5RqDMvfJJF+TwvuhnurmQk1w@mail.gmail.com>
 <2927458.4ozSLghtXU@phil>
Message-ID: <CAD=FV=VBiUvRxh4b50eHdToywyzhvsi0nX_fLv1pJKrNiOuoZg@mail.gmail.com>

Hi,

On Mon, May 9, 2016 at 4:40 AM, Heiko Stuebner <heiko at sntech.de> wrote:
> Am Donnerstag, 5. Mai 2016, 17:35:03 schrieb Doug Anderson:
>> Heiko,
>>
>> On Mon, May 2, 2016 at 9:36 AM, Heiko Stuebner <heiko at sntech.de> wrote:
>> > Given a hirarchy of clk1 -> [div] -> clk2, when the rate of clk1 gets
>> > changed, clk2 changes as well as the divider stays the same. There may
>> > be cases where a user of clk2 needs it at a specific rate, so clk2
>> > needs to be readjusted for the changed rate of clk1.
>> >
>> > So if a rate was requested for the clock, and its rate changed during
>> > the underlying rate-change, with this change the clock framework now
>> > tries to readjust the rate back to/near the requested one.
>> >
>> > The whole process is protected by a new clock-flag to not force this
>> > behaviour change onto every clock defined in the ccf.
>>
>> I'm not an expert on CCF details, but presumably you need to be really
>> careful here.  Is there any way you could get an infinite loop here
>> where you ping-pong between two people trying to control their parent
>> clock?  Right now I see mutual recursion between
>> clk_core_set_rate_nolock() and clk_change_rate() and no base case.
>>
>> Specifically if there's a path (because of CLK_SET_RATE_PARENT) where
>> setting a clock rate on "clk2" in your example can cause a rate change
>> of "clk1" I worry that we'll be in trouble.  Maybe a requirement of
>> your patch is that no such path exists?  ...or maybe something in the
>> code prevents this...
>
> This was one of my worries as well, which is why the flag exists in the first
> place, right now offloading the requirement to check for such conflict cases to
> the clock-tree creator.

If that's the case, it needs to be documented somewhere.  Without some
documentation this flag sounds like a flag that everyone would of
course want everywhere.


> I think one possible test to add could be to check for conflicts between
> CLK_SET_RATE_PARENT and this new flag.
>
> Aka in clk-init once encountering the CLK_KEEP_REQRATE, go up through parent
> clocks as long as CLK_SET_RATE_PARENT is set and if we encounter a parent
> with num_children > 1 (aka a shared base-clock, like a PLL on rockchip)
> unset CLK_KEEP_REQRATE, as it would like introduce that ping-pong game.
>
> Hmm, although this test would also fire in cases like Rockchip's fractional
> dividers, where there is the common pll-select-mux+divider and after that
> the mux selecting between that or having the fractional-divider in between
> as well.
>
> I guess it can get hairy to detect such cases sucessfully.

Wouldn't this logic work?

1. Walk up through parents as long as CLK_SET_RATE_PARENT is set.  Add
to "ancestors" list.

2. Walk down through children of "ancestors" as long as
CLK_SET_RATE_PARENT is set in the child.

3. If CLK_KEEP_REQRATE is found in one of those children and we're not
the original clock then it's an error.


Actually, though, it seems like there's a much easier rule.  For now,
just make CLK_SET_RATE_PARENT and CLK_KEEP_REQRATE mutually exclusive.
You can choose to react to your parent's rate or you can choose to
affect your parent's rate, but not both.

In your current patch 3/3 you actually set both, but I don't think you
really need to do you?


>> > Signed-off-by: Heiko Stuebner <heiko at sntech.de>
>> > ---
>> >
>> >  drivers/clk/clk.c            | 13 +++++++++++--
>> >  include/linux/clk-provider.h |  1 +
>> >  2 files changed, 12 insertions(+), 2 deletions(-)
>> >
>> > diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c
>> > index 65e0aad..22be369 100644
>> > --- a/drivers/clk/clk.c
>> > +++ b/drivers/clk/clk.c
>> > @@ -1410,6 +1410,9 @@ static struct clk_core
>> > *clk_propagate_rate_change(struct clk_core *core,>
>> >         return fail_clk;
>> >
>> >  }
>> >
>> > +static int clk_core_set_rate_nolock(struct clk_core *core,
>> > +                                   unsigned long req_rate);
>> > +
>> >
>> >  /*
>> >
>> >   * walk down a subtree and set the new rates notifying the rate
>> >   * change on the way
>> >
>> > @@ -1494,6 +1497,12 @@ static void clk_change_rate(struct clk_core
>> > *core)
>> >
>> >         /* handle the new child who might not be in core->children yet
>> >         */
>> >         if (core->new_child)
>> >
>> >                 clk_change_rate(core->new_child);
>> >
>> > +
>> > +       /* handle a changed clock that needs to readjust its rate */
>> > +       if (core->flags & CLK_KEEP_REQ_RATE && core->req_rate
>> > +                                           && core->new_rate !=
>> > old_rate
>> > +                                           && core->new_rate !=
>> > core->req_rate) +               clk_core_set_rate_nolock(core,
>> > core->req_rate);
>>
>> I guess we don't care about errors here?
>>
>> ...maybe (?) we could ignore errors if we validated this rate change
>> with PRE_RATE_CHANGE before attempting to change the parent clock, but
>> I don't see the code doing this unless I missed it.
>
> It's more like what would you want to do in the error/failure cases.
>
> So far I was going by the assumption we're going to change the clock anyway
> and just try to pull marked clocks along, so in the error case it would just
> fall back to the current behaviour.

In the very least it should cause a warning to be printed.  By
introducing a new flag you've changed the expectations and I don't
think a user would expect to fall back to the old behavior without at
least an warning.

I think it still makes sense to pre-validate your change in
PRE_RATE_CHANGE, of course.


-Doug


From dianders at chromium.org  Mon May  9 09:31:54 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 9 May 2016 09:31:54 -0700
Subject: [PATCH 2/2] dt-bindings: rockchip-dw-mshc: add rockchip,
 default-drv-phase
In-Reply-To: <b15dcb4f-1584-8219-2fe0-97eecb0c64a6@rock-chips.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
 <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=WSkBwBjVsRoDsfjD+sNfR70mKGRA0khjPKKW0zS2=PTw@mail.gmail.com>
 <b15dcb4f-1584-8219-2fe0-97eecb0c64a6@rock-chips.com>
Message-ID: <CAD=FV=XToSzqSh=SShHuQU9W_m7gfyQn8wRXkLy79t+tnqZknA@mail.gmail.com>

Hi,

On Mon, May 9, 2016 at 4:12 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> 1. Specifying a single number for this property in terms of "degrees"
>> is probably not right.  The whole point of setting the "drive phase"
>> is to meet hold times, which are specified in the spec in terms of ns
>> in the spec and also specified differently for different SD/MMC speed
>> modes.  Note also that "phase" translates to very different delays (in
>> terms of ns) depending on the clock rate:
>>
>> At 400 kHz, period is 2.5 us, so 90 degree phase offset is a delay of 625
>> ns
>> At 25 MHz, period is 40 ns, so a 90 degree phase offset represents a
>> delay of 10 ns.
>> At 50 MHz, period is 20 ns, so a 90 degree phase offset represents a
>> delay of 5 ns.
>> At 200 MHz, period is period is 5 ns, so a 90 degree phase offset
>> represents a delay of 1.25 ns.
>
>
> yes, if we use degrees only(0/90/180/270), the timing is always right.
> But considering the delay number, we need to do some crazy calculation
> in the set_ios callback.

Great, so let's limit it to 0/90/180/270 for the drive phase offset.
We don't need lots of precision for the drive phase offset (right?)
and accuracy is more important.


>> 2. As I understand it, the value needed for the drive phase is not
>> board specific unless you've got super crazy layout on a board (where
>> the clock line takes a very different path than everything else).
>> It's also not even terribly SoC-specific unless you've got some very
>> strange incarnation of dw_mmc that has very different internal delays
>> than everyone else.  Said another way, until we see an instance of an
>> SoC/board that really needs to do things special I'd say that we
>> should just implement this all in code (no device tree bindings).
>>
>
> I'm prone to think it should be Soc specific if making sure the layout
> for data lines is in equal length.

Sure, it can be SoC specific.  ...though at the moment, I'd bet that
you can come up with a single rule for the drive phase offset that
will work for every Rockchip SoC produced so far, especially if you
are using only 0/90/180/270.  I'd imagine that they all have similar
enough internal delays.


>> 3. If this property was actually board specific and actually needed to
>> be tuned board-by-board, you'd have a bug because your new device tree
>> bindings are not backward compatible and you'd probably be breaking
>> old boards.  Specifically you're changing the definition of what
>> happens when "rockchip,default-drv-phase" is not specified.  Old
>> behavior was to leave the value that was setup by the firmware (or
>> perhaps the hardware default if the firmware didn't touch this).
>
>
> drv_phase is for all the data lines instead of tuning the lines
> one-by-one. So this patch can't save the terrible board layout.
> But I agree that it will break the compatibility backward if firware
> touch this value.
>
>>
>> ---
>>
>> OK, so what should we do?
>>
>> We could certainly do lots of crazy math to come up with the ideal
>> hold time for all different speed modes and all different types of
>> cards.  With my reading of the Designware Databook this would mean
>> that somewhere we'd want to specify which delay method we're using
>> (phase shift vs. delay line) and how long all the delays timings all
>> are on your particular SoC.  That all sounds quite difficult, though.
>
>
> delay line is diff from chip to chip, soc-to-soc, board-to-board. For
> sample-phase we have tuning process and re-tune, but not for drv-phase.
> So We bascially should avoid to use it for drv-phase. Another
> consideration is the temperature drift of delay line.
>
> Maybe we should do some tricky limitation on clk-mmc-phase to only
> support fixed degrees?

As per above, let's not use delay line for drive delay.  On all
Rockchip SoCs that I have seen it's possible to make 0/90/180/270 very
accurately.  That means no board-to-board differences.  Current
mainline Linux kernel source code will always make 0/90/180/270 using
phase offset (not delay line).

For sampling we use tuning and using the delay elements makes some
sense (since 90 degrees is not quite accurate enough to fully tune
UHS).  ...but for driving where the only requirement is hold times we
don't need delay elements.


>> Probably you could just add a simple function that looked at the clock
>> and speed mode and always chose an offset of 90 or 180 degrees.  At
>> least on Rockchip devices you can be certain that you can make 90 and
>> 180 degrees using phase shifts and thus the timings should be
>> consistent.  By default you could just always choose 180.  The
>> Designware databook has some examples where it picked 90 degrees
>> (SDR50, DDR50, SDR25, MMC High Speed), but I'm not enough of an MMC
>> expert to know if there is some benefit to choosing 90.  Would we
>> violate any specs if we just chose 180 degrees all the time everywhere
>> on all Rockchip devices?
>
>
> It needs more waveform test to see how things going. But most of
> rockchip platforms in the pass years didn't touch drv-phase stuff not
> only in kernel but also in firmware, then we still cannot see the
> violation against the spec when using defalut reset value, namely 180, for
> drv-phase.

Right, most Rockchip platforms simply don't touch this and it works
OK.  ...but I don't think it defaults to 180.  Grepping through on my
veyron (rk3288) device shows

       sdio1_drv - 90
       sdio0_drv - 90
       sdmmc_drv - 90
       emmc_drv -180

...and, as we've seen, these values appear to be 270 on some other SoCs.


The claim from the Designware Databook says that SDR104 and SDR12, and
identification mode need 180 degrees to work properly.  It would be
interesting to hook up rk3288 to a signal analyzer and see hold times
are OK or if we need to move up to 180 degrees for those modes.

Note that the Designware Databook assumes "Delay_O" of 1.4ns.  If
yours is shorter then maybe 90 degrees is OK for those modes?


Also: I still haven't heard whether there is any downside to using 180
degrees for modes that only require 90 degrees.  Does it cause
problems to just always use 180 degrees?  If not, we could possibly
use 180 degrees everywhere and just hardcode it?


...but if 180 is ideal everywhere, can you answer:

* Why does dw_mmc manual spend so much time talking about it?  It
could just say "set to 180 degrees".

* Why do Rockchip SoCs default to values that are not 180 degrees?

-Doug


From sboyd at codeaurora.org  Mon May  9 16:03:28 2016
From: sboyd at codeaurora.org (Stephen Boyd)
Date: Mon, 9 May 2016 16:03:28 -0700
Subject: [PATCH 4/7] clk: rockchip: abstract pll get-params and
 set-params operations
In-Reply-To: <3451726.6PKcY6Rd6y@phil>
References: <1461849075-8310-1-git-send-email-heiko@sntech.de>
 <1461849075-8310-5-git-send-email-heiko@sntech.de>
 <20160506225543.GF3492@codeaurora.org> <3451726.6PKcY6Rd6y@phil>
Message-ID: <20160509230328.GA3492@codeaurora.org>

On 05/08, Heiko Stuebner wrote:
> 
> I think the "flat design" is what we have right now. The problem is that the 
> core code is pretty similar and only the hardware-specific accesses are 
> special, thus the later indirection.

Right, which is where having some functions that manipulate
register values in a generic way lets us consolidate the common
code into one place while leaving the hardware specific accesses
in the clk ops before or after calling the common functions.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From sboyd at codeaurora.org  Mon May  9 16:05:16 2016
From: sboyd at codeaurora.org (Stephen Boyd)
Date: Mon, 9 May 2016 16:05:16 -0700
Subject: [GIT PULL] rockchip clock changes for 4.7 part 4 - some more fixes
In-Reply-To: <16076636.fp1YCeqDWQ@phil>
References: <16076636.fp1YCeqDWQ@phil>
Message-ID: <20160509230516.GB3492@codeaurora.org>

On 05/09, Heiko St?bner wrote:
> Hi Mike, Stephen,
> 
> A fixup for a rk3399 clock name as well as the GRF-portions of
> my cleanup series. As Stephen had some mild reservations about the
> introduced indirection in the pll parts and we don't save to much lines
> with my modifications for the currently supported pll-types, I think it's
> easier to postpone those until the next new pll type comes around.
> 
> Maybe it even has some completely different properties to handle where
> the current "simplification" might even be counter-productive :-) .
> 
> So please pull if possible.
> 
> Thanks
> Heiko
> 
> 
> The following changes since commit fd8bc829336a24b770247eb893111bcb8f1ddedb:
> 
>   clk: rockchip: fix the rk3399 cifout clock (2016-04-25 22:54:51 +0200)
> 
> are available in the git repository at:
> 
>   git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git tags/v4.7-rockchip-clk4

Thanks. Pulled.

-- 
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum,
a Linux Foundation Collaborative Project


From w.egorov at phytec.de  Mon May  9 23:51:45 2016
From: w.egorov at phytec.de (Wadim Egorov)
Date: Tue, 10 May 2016 08:51:45 +0200
Subject: [PATCH v4 3/7] mfd: RK808: Add RK818 support
In-Reply-To: <1461682450-22173-4-git-send-email-w.egorov@phytec.de>
References: <1461682450-22173-1-git-send-email-w.egorov@phytec.de>
 <1461682450-22173-4-git-send-email-w.egorov@phytec.de>
Message-ID: <57318501.4060900@phytec.de>

Ping.

Do you have any more comments?

On 26.04.2016 16:54, Wadim Egorov wrote:
> The RK818 chip is a power management IC for multimedia and handheld
> devices. It contains the following components:
>
> - Regulators
> - RTC
> - Clkout
> - battery support
>
> Both chips RK808 and RK818 are using a similar register map.
> So we can reuse the RTC and Clkout functionality.
>
> Signed-off-by: Wadim Egorov <w.egorov at phytec.de>
> ---
> Changes since v3:
> - fixed file and module descriptions
> ---
>  drivers/mfd/Kconfig       |   4 +-
>  drivers/mfd/rk808.c       | 229 +++++++++++++++++++++++++++++++++++++++-------
>  include/linux/mfd/rk808.h | 162 ++++++++++++++++++++++++++++++--
>  3 files changed, 349 insertions(+), 46 deletions(-)
>
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index eea61e3..0a5b1c0 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -814,13 +814,13 @@ config MFD_RC5T583
>  	  different functionality of the device.
>  
>  config MFD_RK808
> -	tristate "Rockchip RK808 Power Management chip"
> +	tristate "Rockchip RK808/RK818 Power Management chip"
>  	depends on I2C && OF
>  	select MFD_CORE
>  	select REGMAP_I2C
>  	select REGMAP_IRQ
>  	help
> -	  If you say yes here you get support for the RK808
> +	  If you say yes here you get support for the RK808 and RK818
>  	  Power Management chips.
>  	  This driver provides common support for accessing the device
>  	  through I2C interface. The device supports multiple sub-devices
> diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
> index 4b1e439..9bb7e8c 100644
> --- a/drivers/mfd/rk808.c
> +++ b/drivers/mfd/rk808.c
> @@ -1,11 +1,15 @@
>  /*
> - * MFD core driver for Rockchip RK808
> + * MFD core driver for Rockchip RK808/RK818
>   *
>   * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
>   *
>   * Author: Chris Zhong <zyw at rock-chips.com>
>   * Author: Zhang Qing <zhangqing at rock-chips.com>
>   *
> + * Copyright (C) 2016 PHYTEC Messtechnik GmbH
> + *
> + * Author: Wadim Egorov <w.egorov at phytec.de>
> + *
>   * This program is free software; you can redistribute it and/or modify it
>   * under the terms and conditions of the GNU General Public License,
>   * version 2, as published by the Free Software Foundation.
> @@ -22,12 +26,7 @@
>  #include <linux/mfd/core.h>
>  #include <linux/module.h>
>  #include <linux/regmap.h>
> -
> -struct rk808_reg_data {
> -	int addr;
> -	int mask;
> -	int value;
> -};
> +#include <linux/of_device.h>
>  
>  static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
>  {
> @@ -57,6 +56,14 @@ static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
>  	return false;
>  }
>  
> +static const struct regmap_config rk818_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.max_register = RK818_USB_CTRL_REG,
> +	.cache_type = REGCACHE_RBTREE,
> +	.volatile_reg = rk808_is_volatile_reg,
> +};
> +
>  static const struct regmap_config rk808_regmap_config = {
>  	.reg_bits = 8,
>  	.val_bits = 8,
> @@ -83,7 +90,17 @@ static const struct mfd_cell rk808s[] = {
>  	},
>  };
>  
> -static const struct rk808_reg_data pre_init_reg[] = {
> +static const struct mfd_cell rk818s[] = {
> +	{ .name = "rk808-clkout", },
> +	{ .name = "rk808-regulator", },
> +	{
> +		.name = "rk808-rtc",
> +		.num_resources = ARRAY_SIZE(rtc_resources),
> +		.resources = &rtc_resources[0],
> +	},
> +};
> +
> +static const struct rk8xx_reg_data rk808_pre_init_reg[] = {
>  	{ RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK,  BUCK_ILMIN_150MA },
>  	{ RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK,  BUCK_ILMIN_200MA },
>  	{ RK808_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
> @@ -94,6 +111,22 @@ static const struct rk808_reg_data pre_init_reg[] = {
>  						    VB_LO_SEL_3500MV },
>  };
>  
> +static const struct rk8xx_reg_data rk818_pre_init_reg[] = {
> +	{ RK818_USB_CTRL_REG,	RK818_USB_ILIM_SEL_MASK,
> +						RK818_USB_ILMIN_2000MA },
> +	/* close charger when usb lower then 3.4V */
> +	{ RK818_USB_CTRL_REG,	RK818_USB_CHG_SD_VSEL_MASK, (0x7 << 4) },
> +	/* no action when vref */
> +	{ RK818_H5V_EN_REG,	BIT(1),		RK818_REF_RDY_CTRL },
> +	/* enable HDMI 5V */
> +	{ RK818_H5V_EN_REG,	BIT(0),		RK818_H5V_EN },
> +	/* improve efficiency */
> +	{ RK818_BUCK2_CONFIG_REG, BUCK2_RATE_MASK,	BUCK_ILMIN_250MA },
> +	{ RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK,	BUCK_ILMIN_250MA },
> +	{ RK818_BOOST_CONFIG_REG, BOOST_ILMIN_MASK,	BOOST_ILMIN_100MA },
> +	{ RK808_VB_MON_REG,	MASK_ALL,	VB_LO_ACT | VB_LO_SEL_3500MV },
> +};
> +
>  static const struct regmap_irq rk808_irqs[] = {
>  	/* INT_STS */
>  	[RK808_IRQ_VOUT_LO] = {
> @@ -136,6 +169,76 @@ static const struct regmap_irq rk808_irqs[] = {
>  	},
>  };
>  
> +static const struct regmap_irq rk818_irqs[] = {
> +	/* INT_STS */
> +	[RK818_IRQ_VOUT_LO] = {
> +		.mask = RK818_IRQ_VOUT_LO_MSK,
> +		.reg_offset = 0,
> +	},
> +	[RK818_IRQ_VB_LO] = {
> +		.mask = RK818_IRQ_VB_LO_MSK,
> +		.reg_offset = 0,
> +	},
> +	[RK818_IRQ_PWRON] = {
> +		.mask = RK818_IRQ_PWRON_MSK,
> +		.reg_offset = 0,
> +	},
> +	[RK818_IRQ_PWRON_LP] = {
> +		.mask = RK818_IRQ_PWRON_LP_MSK,
> +		.reg_offset = 0,
> +	},
> +	[RK818_IRQ_HOTDIE] = {
> +		.mask = RK818_IRQ_HOTDIE_MSK,
> +		.reg_offset = 0,
> +	},
> +	[RK818_IRQ_RTC_ALARM] = {
> +		.mask = RK818_IRQ_RTC_ALARM_MSK,
> +		.reg_offset = 0,
> +	},
> +	[RK818_IRQ_RTC_PERIOD] = {
> +		.mask = RK818_IRQ_RTC_PERIOD_MSK,
> +		.reg_offset = 0,
> +	},
> +	[RK818_IRQ_USB_OV] = {
> +		.mask = RK818_IRQ_USB_OV_MSK,
> +		.reg_offset = 0,
> +	},
> +
> +	/* INT_STS2 */
> +	[RK818_IRQ_PLUG_IN] = {
> +		.mask = RK818_IRQ_PLUG_IN_MSK,
> +		.reg_offset = 1,
> +	},
> +	[RK818_IRQ_PLUG_OUT] = {
> +		.mask = RK818_IRQ_PLUG_OUT_MSK,
> +		.reg_offset = 1,
> +	},
> +	[RK818_IRQ_CHG_OK] = {
> +		.mask = RK818_IRQ_CHG_OK_MSK,
> +		.reg_offset = 1,
> +	},
> +	[RK818_IRQ_CHG_TE] = {
> +		.mask = RK818_IRQ_CHG_TE_MSK,
> +		.reg_offset = 1,
> +	},
> +	[RK818_IRQ_CHG_TS1] = {
> +		.mask = RK818_IRQ_CHG_TS1_MSK,
> +		.reg_offset = 1,
> +	},
> +	[RK818_IRQ_TS2] = {
> +		.mask = RK818_IRQ_TS2_MSK,
> +		.reg_offset = 1,
> +	},
> +	[RK818_IRQ_CHG_CVTLIM] = {
> +		.mask = RK818_IRQ_CHG_CVTLIM_MSK,
> +		.reg_offset = 1,
> +	},
> +	[RK818_IRQ_DISCHG_ILIM] = {
> +		.mask = RK818_IRQ_DISCHG_ILIM_MSK,
> +		.reg_offset = 1,
> +	},
> +};
> +
>  static struct regmap_irq_chip rk808_irq_chip = {
>  	.name = "rk808",
>  	.irqs = rk808_irqs,
> @@ -148,6 +251,18 @@ static struct regmap_irq_chip rk808_irq_chip = {
>  	.init_ack_masked = true,
>  };
>  
> +static struct regmap_irq_chip rk818_irq_chip = {
> +	.name = "rk818",
> +	.irqs = rk818_irqs,
> +	.num_irqs = ARRAY_SIZE(rk818_irqs),
> +	.num_regs = 2,
> +	.irq_reg_stride = 2,
> +	.status_base = RK818_INT_STS_REG1,
> +	.mask_base = RK818_INT_STS_MSK_REG1,
> +	.ack_base = RK818_INT_STS_REG1,
> +	.init_ack_masked = true,
> +};
> +
>  static struct i2c_client *rk808_i2c_client;
>  static void rk808_device_shutdown(void)
>  {
> @@ -167,6 +282,48 @@ static void rk808_device_shutdown(void)
>  		dev_err(&rk808_i2c_client->dev, "power off error!\n");
>  }
>  
> +static const struct of_device_id rk808_of_match[] = {
> +	{ .compatible = "rockchip,rk808", .data = (void *) RK808_ID },
> +	{ .compatible = "rockchip,rk818", .data = (void *) RK818_ID },
> +	{ },
> +};
> +MODULE_DEVICE_TABLE(of, rk808_of_match);
> +
> +static int rk8xx_match_device(struct rk808 *rk808, struct device *dev)
> +{
> +	const struct of_device_id *of_id;
> +
> +	of_id = of_match_device(rk808_of_match, dev);
> +	if (!of_id) {
> +		dev_err(dev, "Unable to match OF ID\n");
> +		return -ENODEV;
> +	}
> +	rk808->variant = (long) of_id->data;
> +
> +	switch (rk808->variant) {
> +	case RK808_ID:
> +		rk808->nr_cells = ARRAY_SIZE(rk808s);
> +		rk808->cells = rk808s;
> +		rk808->regmap_cfg = &rk808_regmap_config;
> +		rk808->regmap_irq_chip = &rk808_irq_chip;
> +		rk808->pre_init_reg = rk808_pre_init_reg;
> +		rk808->nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
> +		break;
> +	case RK818_ID:
> +		rk808->nr_cells = ARRAY_SIZE(rk818s);
> +		rk808->cells = rk818s;
> +		rk808->regmap_cfg = &rk818_regmap_config;
> +		rk808->regmap_irq_chip = &rk818_irq_chip;
> +		rk808->pre_init_reg = rk818_pre_init_reg;
> +		rk808->nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
> +		break;
> +	default:
> +		dev_err(dev, "unsupported RK8XX ID %lu\n", rk808->variant);
> +		return -EINVAL;
> +	}
> +
> +	return 0;
> +}
>  static int rk808_probe(struct i2c_client *client,
>  		       const struct i2c_device_id *id)
>  {
> @@ -176,45 +333,51 @@ static int rk808_probe(struct i2c_client *client,
>  	int ret;
>  	int i;
>  
> -	if (!client->irq) {
> -		dev_err(&client->dev, "No interrupt support, no core IRQ\n");
> -		return -EINVAL;
> -	}
> -
>  	rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL);
>  	if (!rk808)
>  		return -ENOMEM;
>  
> -	rk808->regmap = devm_regmap_init_i2c(client, &rk808_regmap_config);
> +	ret = rk8xx_match_device(rk808, &client->dev);
> +	if (ret)
> +		return ret;
> +
> +	rk808->i2c = client;
> +	i2c_set_clientdata(client, rk808);
> +
> +	rk808->regmap = devm_regmap_init_i2c(client, rk808->regmap_cfg);
>  	if (IS_ERR(rk808->regmap)) {
>  		dev_err(&client->dev, "regmap initialization failed\n");
>  		return PTR_ERR(rk808->regmap);
>  	}
>  
> -	for (i = 0; i < ARRAY_SIZE(pre_init_reg); i++) {
> -		ret = regmap_update_bits(rk808->regmap, pre_init_reg[i].addr,
> -					 pre_init_reg[i].mask,
> -					 pre_init_reg[i].value);
> -		if (ret) {
> -			dev_err(&client->dev,
> -				"0x%x write err\n", pre_init_reg[i].addr);
> -			return ret;
> -		}
> +	if (!client->irq) {
> +		dev_err(&client->dev, "No interrupt support, no core IRQ\n");
> +		return -EINVAL;
>  	}
>  
>  	ret = regmap_add_irq_chip(rk808->regmap, client->irq,
>  				  IRQF_ONESHOT, -1,
> -				  &rk808_irq_chip, &rk808->irq_data);
> +				  rk808->regmap_irq_chip, &rk808->irq_data);
>  	if (ret) {
>  		dev_err(&client->dev, "Failed to add irq_chip %d\n", ret);
>  		return ret;
>  	}
>  
> -	rk808->i2c = client;
> -	i2c_set_clientdata(client, rk808);
> +	for (i = 0; i < rk808->nr_pre_init_regs; i++) {
> +		ret = regmap_update_bits(rk808->regmap,
> +					rk808->pre_init_reg[i].addr,
> +					rk808->pre_init_reg[i].mask,
> +					rk808->pre_init_reg[i].value);
> +		if (ret) {
> +			dev_err(&client->dev,
> +				"0x%x write err\n",
> +				rk808->pre_init_reg[i].addr);
> +			return ret;
> +		}
> +	}
>  
> -	ret = mfd_add_devices(&client->dev, -1,
> -			      rk808s, ARRAY_SIZE(rk808s),
> +	ret = mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
> +			      rk808->cells, rk808->nr_cells,
>  			      NULL, 0, regmap_irq_get_domain(rk808->irq_data));
>  	if (ret) {
>  		dev_err(&client->dev, "failed to add MFD devices %d\n", ret);
> @@ -246,14 +409,9 @@ static int rk808_remove(struct i2c_client *client)
>  	return 0;
>  }
>  
> -static const struct of_device_id rk808_of_match[] = {
> -	{ .compatible = "rockchip,rk808" },
> -	{ },
> -};
> -MODULE_DEVICE_TABLE(of, rk808_of_match);
> -
>  static const struct i2c_device_id rk808_ids[] = {
>  	{ "rk808" },
> +	{ "rk818" },
>  	{ },
>  };
>  MODULE_DEVICE_TABLE(i2c, rk808_ids);
> @@ -273,4 +431,5 @@ module_i2c_driver(rk808_i2c_driver);
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Chris Zhong <zyw at rock-chips.com>");
>  MODULE_AUTHOR("Zhang Qing <zhangqing at rock-chips.com>");
> -MODULE_DESCRIPTION("RK808 PMIC driver");
> +MODULE_AUTHOR("Wadim Egorov <w.egorov at phytec.de>");
> +MODULE_DESCRIPTION("RK808/RK818 PMIC driver");
> diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h
> index 441b6ee..5ce810c 100644
> --- a/include/linux/mfd/rk808.h
> +++ b/include/linux/mfd/rk808.h
> @@ -1,11 +1,15 @@
>  /*
> - * rk808.h for Rockchip RK808
> + * Register definitions for Rockchip's RK808/RK818 PMIC
>   *
>   * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
>   *
>   * Author: Chris Zhong <zyw at rock-chips.com>
>   * Author: Zhang Qing <zhangqing at rock-chips.com>
>   *
> + * Copyright (C) 2016 PHYTEC Messtechnik GmbH
> + *
> + * Author: Wadim Egorov <w.egorov at phytec.de>
> + *
>   * This program is free software; you can redistribute it and/or modify it
>   * under the terms and conditions of the GNU General Public License,
>   * version 2, as published by the Free Software Foundation.
> @@ -16,8 +20,8 @@
>   * more details.
>   */
>  
> -#ifndef __LINUX_REGULATOR_rk808_H
> -#define __LINUX_REGULATOR_rk808_H
> +#ifndef __LINUX_REGULATOR_RK808_H
> +#define __LINUX_REGULATOR_RK808_H
>  
>  #include <linux/regulator/machine.h>
>  #include <linux/regmap.h>
> @@ -28,7 +32,7 @@
>  
>  #define RK808_DCDC1	0 /* (0+RK808_START) */
>  #define RK808_LDO1	4 /* (4+RK808_START) */
> -#define RK808_NUM_REGULATORS   14
> +#define RK808_NUM_REGULATORS	14
>  
>  enum rk808_reg {
>  	RK808_ID_DCDC1,
> @@ -115,7 +119,92 @@ enum rk808_reg {
>  #define RK808_INT_STS_MSK_REG2	0x4f
>  #define RK808_IO_POL_REG	0x50
>  
> -/* IRQ Definitions */
> +/* RK818 */
> +#define RK818_DCDC1			0
> +#define RK818_LDO1			4
> +#define RK818_NUM_REGULATORS		17
> +
> +enum rk818_reg {
> +	RK818_ID_DCDC1,
> +	RK818_ID_DCDC2,
> +	RK818_ID_DCDC3,
> +	RK818_ID_DCDC4,
> +	RK818_ID_BOOST,
> +	RK818_ID_LDO1,
> +	RK818_ID_LDO2,
> +	RK818_ID_LDO3,
> +	RK818_ID_LDO4,
> +	RK818_ID_LDO5,
> +	RK818_ID_LDO6,
> +	RK818_ID_LDO7,
> +	RK818_ID_LDO8,
> +	RK818_ID_LDO9,
> +	RK818_ID_SWITCH,
> +	RK818_ID_HDMI_SWITCH,
> +	RK818_ID_OTG_SWITCH,
> +};
> +
> +#define RK818_DCDC_EN_REG		0x23
> +#define RK818_LDO_EN_REG		0x24
> +#define RK818_SLEEP_SET_OFF_REG1	0x25
> +#define RK818_SLEEP_SET_OFF_REG2	0x26
> +#define RK818_DCDC_UV_STS_REG		0x27
> +#define RK818_DCDC_UV_ACT_REG		0x28
> +#define RK818_LDO_UV_STS_REG		0x29
> +#define RK818_LDO_UV_ACT_REG		0x2a
> +#define RK818_DCDC_PG_REG		0x2b
> +#define RK818_LDO_PG_REG		0x2c
> +#define RK818_VOUT_MON_TDB_REG		0x2d
> +#define RK818_BUCK1_CONFIG_REG		0x2e
> +#define RK818_BUCK1_ON_VSEL_REG		0x2f
> +#define RK818_BUCK1_SLP_VSEL_REG	0x30
> +#define RK818_BUCK2_CONFIG_REG		0x32
> +#define RK818_BUCK2_ON_VSEL_REG		0x33
> +#define RK818_BUCK2_SLP_VSEL_REG	0x34
> +#define RK818_BUCK3_CONFIG_REG		0x36
> +#define RK818_BUCK4_CONFIG_REG		0x37
> +#define RK818_BUCK4_ON_VSEL_REG		0x38
> +#define RK818_BUCK4_SLP_VSEL_REG	0x39
> +#define RK818_BOOST_CONFIG_REG		0x3a
> +#define RK818_LDO1_ON_VSEL_REG		0x3b
> +#define RK818_LDO1_SLP_VSEL_REG		0x3c
> +#define RK818_LDO2_ON_VSEL_REG		0x3d
> +#define RK818_LDO2_SLP_VSEL_REG		0x3e
> +#define RK818_LDO3_ON_VSEL_REG		0x3f
> +#define RK818_LDO3_SLP_VSEL_REG		0x40
> +#define RK818_LDO4_ON_VSEL_REG		0x41
> +#define RK818_LDO4_SLP_VSEL_REG		0x42
> +#define RK818_LDO5_ON_VSEL_REG		0x43
> +#define RK818_LDO5_SLP_VSEL_REG		0x44
> +#define RK818_LDO6_ON_VSEL_REG		0x45
> +#define RK818_LDO6_SLP_VSEL_REG		0x46
> +#define RK818_LDO7_ON_VSEL_REG		0x47
> +#define RK818_LDO7_SLP_VSEL_REG		0x48
> +#define RK818_LDO8_ON_VSEL_REG		0x49
> +#define RK818_LDO8_SLP_VSEL_REG		0x4a
> +#define RK818_BOOST_LDO9_ON_VSEL_REG	0x54
> +#define RK818_BOOST_LDO9_SLP_VSEL_REG	0x55
> +#define RK818_DEVCTRL_REG		0x4b
> +#define RK818_INT_STS_REG1		0X4c
> +#define RK818_INT_STS_MSK_REG1		0x4d
> +#define RK818_INT_STS_REG2		0x4e
> +#define RK818_INT_STS_MSK_REG2		0x4f
> +#define RK818_IO_POL_REG		0x50
> +#define RK818_H5V_EN_REG		0x52
> +#define RK818_SLEEP_SET_OFF_REG3	0x53
> +#define RK818_BOOST_LDO9_ON_VSEL_REG	0x54
> +#define RK818_BOOST_LDO9_SLP_VSEL_REG	0x55
> +#define RK818_BOOST_CTRL_REG		0x56
> +#define RK818_DCDC_ILMAX		0x90
> +#define RK818_USB_CTRL_REG		0xa1
> +
> +#define RK818_H5V_EN			BIT(0)
> +#define RK818_REF_RDY_CTRL		BIT(1)
> +#define RK818_USB_ILIM_SEL_MASK		0xf
> +#define RK818_USB_ILMIN_2000MA		0x7
> +#define RK818_USB_CHG_SD_VSEL_MASK	0x70
> +
> +/* RK808 IRQ Definitions */
>  #define RK808_IRQ_VOUT_LO	0
>  #define RK808_IRQ_VB_LO		1
>  #define RK808_IRQ_PWRON		2
> @@ -137,6 +226,43 @@ enum rk808_reg {
>  #define RK808_IRQ_PLUG_IN_INT_MSK	BIT(0)
>  #define RK808_IRQ_PLUG_OUT_INT_MSK	BIT(1)
>  
> +/* RK818 IRQ Definitions */
> +#define RK818_IRQ_VOUT_LO	0
> +#define RK818_IRQ_VB_LO		1
> +#define RK818_IRQ_PWRON		2
> +#define RK818_IRQ_PWRON_LP	3
> +#define RK818_IRQ_HOTDIE	4
> +#define RK818_IRQ_RTC_ALARM	5
> +#define RK818_IRQ_RTC_PERIOD	6
> +#define RK818_IRQ_USB_OV	7
> +#define RK818_IRQ_PLUG_IN	8
> +#define RK818_IRQ_PLUG_OUT	9
> +#define RK818_IRQ_CHG_OK	10
> +#define RK818_IRQ_CHG_TE	11
> +#define RK818_IRQ_CHG_TS1	12
> +#define RK818_IRQ_TS2		13
> +#define RK818_IRQ_CHG_CVTLIM	14
> +#define RK818_IRQ_DISCHG_ILIM	7
> +
> +#define RK818_IRQ_VOUT_LO_MSK		BIT(0)
> +#define RK818_IRQ_VB_LO_MSK		BIT(1)
> +#define RK818_IRQ_PWRON_MSK		BIT(2)
> +#define RK818_IRQ_PWRON_LP_MSK		BIT(3)
> +#define RK818_IRQ_HOTDIE_MSK		BIT(4)
> +#define RK818_IRQ_RTC_ALARM_MSK		BIT(5)
> +#define RK818_IRQ_RTC_PERIOD_MSK	BIT(6)
> +#define RK818_IRQ_USB_OV_MSK		BIT(7)
> +#define RK818_IRQ_PLUG_IN_MSK		BIT(0)
> +#define RK818_IRQ_PLUG_OUT_MSK		BIT(1)
> +#define RK818_IRQ_CHG_OK_MSK		BIT(2)
> +#define RK818_IRQ_CHG_TE_MSK		BIT(3)
> +#define RK818_IRQ_CHG_TS1_MSK		BIT(4)
> +#define RK818_IRQ_TS2_MSK		BIT(5)
> +#define RK818_IRQ_CHG_CVTLIM_MSK	BIT(6)
> +#define RK818_IRQ_DISCHG_ILIM_MSK	BIT(7)
> +
> +#define RK818_NUM_IRQ		16
> +
>  #define RK808_VBAT_LOW_2V8	0x00
>  #define RK808_VBAT_LOW_2V9	0x01
>  #define RK808_VBAT_LOW_3V0	0x02
> @@ -191,9 +317,27 @@ enum {
>  	BOOST_ILMIN_250MA,
>  };
>  
> +enum {
> +	RK808_ID,
> +	RK818_ID,
> +};
> +
> +struct rk8xx_reg_data {
> +	int addr;
> +	int mask;
> +	int value;
> +};
> +
>  struct rk808 {
> -	struct i2c_client *i2c;
> -	struct regmap_irq_chip_data *irq_data;
> -	struct regmap *regmap;
> +	struct i2c_client		*i2c;
> +	struct regmap_irq_chip_data	*irq_data;
> +	struct regmap			*regmap;
> +	long				variant;
> +	int				nr_cells;
> +	const struct mfd_cell		*cells;
> +	const struct regmap_config	*regmap_cfg;
> +	const struct regmap_irq_chip	*regmap_irq_chip;
> +	const struct rk8xx_reg_data	*pre_init_reg;
> +	int				nr_pre_init_regs;
>  };
> -#endif /* __LINUX_REGULATOR_rk808_H */
> +#endif /* __LINUX_REGULATOR_RK808_H */



From lee.jones at linaro.org  Tue May 10 00:54:38 2016
From: lee.jones at linaro.org (Lee Jones)
Date: Tue, 10 May 2016 08:54:38 +0100
Subject: [PATCH v4 3/7] mfd: RK808: Add RK818 support
In-Reply-To: <57318501.4060900@phytec.de>
References: <1461682450-22173-1-git-send-email-w.egorov@phytec.de>
 <1461682450-22173-4-git-send-email-w.egorov@phytec.de>
 <57318501.4060900@phytec.de>
Message-ID: <20160510075438.GJ19473@dell>

On Tue, 10 May 2016, Wadim Egorov wrote:

> Ping.

Don't ping.  It only serves to annoy!

> Do you have any more comments?

Just re-submit the set with the Acks you've collected.

> On 26.04.2016 16:54, Wadim Egorov wrote:
> > The RK818 chip is a power management IC for multimedia and handheld
> > devices. It contains the following components:
> >
> > - Regulators
> > - RTC
> > - Clkout
> > - battery support
> >
> > Both chips RK808 and RK818 are using a similar register map.
> > So we can reuse the RTC and Clkout functionality.
> >
> > Signed-off-by: Wadim Egorov <w.egorov at phytec.de>
> > ---
> > Changes since v3:
> > - fixed file and module descriptions
> > ---
> >  drivers/mfd/Kconfig       |   4 +-
> >  drivers/mfd/rk808.c       | 229 +++++++++++++++++++++++++++++++++++++++-------
> >  include/linux/mfd/rk808.h | 162 ++++++++++++++++++++++++++++++--
> >  3 files changed, 349 insertions(+), 46 deletions(-)
> >
> > diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> > index eea61e3..0a5b1c0 100644
> > --- a/drivers/mfd/Kconfig
> > +++ b/drivers/mfd/Kconfig
> > @@ -814,13 +814,13 @@ config MFD_RC5T583
> >  	  different functionality of the device.
> >  
> >  config MFD_RK808
> > -	tristate "Rockchip RK808 Power Management chip"
> > +	tristate "Rockchip RK808/RK818 Power Management chip"
> >  	depends on I2C && OF
> >  	select MFD_CORE
> >  	select REGMAP_I2C
> >  	select REGMAP_IRQ
> >  	help
> > -	  If you say yes here you get support for the RK808
> > +	  If you say yes here you get support for the RK808 and RK818
> >  	  Power Management chips.
> >  	  This driver provides common support for accessing the device
> >  	  through I2C interface. The device supports multiple sub-devices
> > diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
> > index 4b1e439..9bb7e8c 100644
> > --- a/drivers/mfd/rk808.c
> > +++ b/drivers/mfd/rk808.c
> > @@ -1,11 +1,15 @@
> >  /*
> > - * MFD core driver for Rockchip RK808
> > + * MFD core driver for Rockchip RK808/RK818
> >   *
> >   * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
> >   *
> >   * Author: Chris Zhong <zyw at rock-chips.com>
> >   * Author: Zhang Qing <zhangqing at rock-chips.com>
> >   *
> > + * Copyright (C) 2016 PHYTEC Messtechnik GmbH
> > + *
> > + * Author: Wadim Egorov <w.egorov at phytec.de>
> > + *
> >   * This program is free software; you can redistribute it and/or modify it
> >   * under the terms and conditions of the GNU General Public License,
> >   * version 2, as published by the Free Software Foundation.
> > @@ -22,12 +26,7 @@
> >  #include <linux/mfd/core.h>
> >  #include <linux/module.h>
> >  #include <linux/regmap.h>
> > -
> > -struct rk808_reg_data {
> > -	int addr;
> > -	int mask;
> > -	int value;
> > -};
> > +#include <linux/of_device.h>
> >  
> >  static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
> >  {
> > @@ -57,6 +56,14 @@ static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
> >  	return false;
> >  }
> >  
> > +static const struct regmap_config rk818_regmap_config = {
> > +	.reg_bits = 8,
> > +	.val_bits = 8,
> > +	.max_register = RK818_USB_CTRL_REG,
> > +	.cache_type = REGCACHE_RBTREE,
> > +	.volatile_reg = rk808_is_volatile_reg,
> > +};
> > +
> >  static const struct regmap_config rk808_regmap_config = {
> >  	.reg_bits = 8,
> >  	.val_bits = 8,
> > @@ -83,7 +90,17 @@ static const struct mfd_cell rk808s[] = {
> >  	},
> >  };
> >  
> > -static const struct rk808_reg_data pre_init_reg[] = {
> > +static const struct mfd_cell rk818s[] = {
> > +	{ .name = "rk808-clkout", },
> > +	{ .name = "rk808-regulator", },
> > +	{
> > +		.name = "rk808-rtc",
> > +		.num_resources = ARRAY_SIZE(rtc_resources),
> > +		.resources = &rtc_resources[0],
> > +	},
> > +};
> > +
> > +static const struct rk8xx_reg_data rk808_pre_init_reg[] = {
> >  	{ RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK,  BUCK_ILMIN_150MA },
> >  	{ RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK,  BUCK_ILMIN_200MA },
> >  	{ RK808_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
> > @@ -94,6 +111,22 @@ static const struct rk808_reg_data pre_init_reg[] = {
> >  						    VB_LO_SEL_3500MV },
> >  };
> >  
> > +static const struct rk8xx_reg_data rk818_pre_init_reg[] = {
> > +	{ RK818_USB_CTRL_REG,	RK818_USB_ILIM_SEL_MASK,
> > +						RK818_USB_ILMIN_2000MA },
> > +	/* close charger when usb lower then 3.4V */
> > +	{ RK818_USB_CTRL_REG,	RK818_USB_CHG_SD_VSEL_MASK, (0x7 << 4) },
> > +	/* no action when vref */
> > +	{ RK818_H5V_EN_REG,	BIT(1),		RK818_REF_RDY_CTRL },
> > +	/* enable HDMI 5V */
> > +	{ RK818_H5V_EN_REG,	BIT(0),		RK818_H5V_EN },
> > +	/* improve efficiency */
> > +	{ RK818_BUCK2_CONFIG_REG, BUCK2_RATE_MASK,	BUCK_ILMIN_250MA },
> > +	{ RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK,	BUCK_ILMIN_250MA },
> > +	{ RK818_BOOST_CONFIG_REG, BOOST_ILMIN_MASK,	BOOST_ILMIN_100MA },
> > +	{ RK808_VB_MON_REG,	MASK_ALL,	VB_LO_ACT | VB_LO_SEL_3500MV },
> > +};
> > +
> >  static const struct regmap_irq rk808_irqs[] = {
> >  	/* INT_STS */
> >  	[RK808_IRQ_VOUT_LO] = {
> > @@ -136,6 +169,76 @@ static const struct regmap_irq rk808_irqs[] = {
> >  	},
> >  };
> >  
> > +static const struct regmap_irq rk818_irqs[] = {
> > +	/* INT_STS */
> > +	[RK818_IRQ_VOUT_LO] = {
> > +		.mask = RK818_IRQ_VOUT_LO_MSK,
> > +		.reg_offset = 0,
> > +	},
> > +	[RK818_IRQ_VB_LO] = {
> > +		.mask = RK818_IRQ_VB_LO_MSK,
> > +		.reg_offset = 0,
> > +	},
> > +	[RK818_IRQ_PWRON] = {
> > +		.mask = RK818_IRQ_PWRON_MSK,
> > +		.reg_offset = 0,
> > +	},
> > +	[RK818_IRQ_PWRON_LP] = {
> > +		.mask = RK818_IRQ_PWRON_LP_MSK,
> > +		.reg_offset = 0,
> > +	},
> > +	[RK818_IRQ_HOTDIE] = {
> > +		.mask = RK818_IRQ_HOTDIE_MSK,
> > +		.reg_offset = 0,
> > +	},
> > +	[RK818_IRQ_RTC_ALARM] = {
> > +		.mask = RK818_IRQ_RTC_ALARM_MSK,
> > +		.reg_offset = 0,
> > +	},
> > +	[RK818_IRQ_RTC_PERIOD] = {
> > +		.mask = RK818_IRQ_RTC_PERIOD_MSK,
> > +		.reg_offset = 0,
> > +	},
> > +	[RK818_IRQ_USB_OV] = {
> > +		.mask = RK818_IRQ_USB_OV_MSK,
> > +		.reg_offset = 0,
> > +	},
> > +
> > +	/* INT_STS2 */
> > +	[RK818_IRQ_PLUG_IN] = {
> > +		.mask = RK818_IRQ_PLUG_IN_MSK,
> > +		.reg_offset = 1,
> > +	},
> > +	[RK818_IRQ_PLUG_OUT] = {
> > +		.mask = RK818_IRQ_PLUG_OUT_MSK,
> > +		.reg_offset = 1,
> > +	},
> > +	[RK818_IRQ_CHG_OK] = {
> > +		.mask = RK818_IRQ_CHG_OK_MSK,
> > +		.reg_offset = 1,
> > +	},
> > +	[RK818_IRQ_CHG_TE] = {
> > +		.mask = RK818_IRQ_CHG_TE_MSK,
> > +		.reg_offset = 1,
> > +	},
> > +	[RK818_IRQ_CHG_TS1] = {
> > +		.mask = RK818_IRQ_CHG_TS1_MSK,
> > +		.reg_offset = 1,
> > +	},
> > +	[RK818_IRQ_TS2] = {
> > +		.mask = RK818_IRQ_TS2_MSK,
> > +		.reg_offset = 1,
> > +	},
> > +	[RK818_IRQ_CHG_CVTLIM] = {
> > +		.mask = RK818_IRQ_CHG_CVTLIM_MSK,
> > +		.reg_offset = 1,
> > +	},
> > +	[RK818_IRQ_DISCHG_ILIM] = {
> > +		.mask = RK818_IRQ_DISCHG_ILIM_MSK,
> > +		.reg_offset = 1,
> > +	},
> > +};
> > +
> >  static struct regmap_irq_chip rk808_irq_chip = {
> >  	.name = "rk808",
> >  	.irqs = rk808_irqs,
> > @@ -148,6 +251,18 @@ static struct regmap_irq_chip rk808_irq_chip = {
> >  	.init_ack_masked = true,
> >  };
> >  
> > +static struct regmap_irq_chip rk818_irq_chip = {
> > +	.name = "rk818",
> > +	.irqs = rk818_irqs,
> > +	.num_irqs = ARRAY_SIZE(rk818_irqs),
> > +	.num_regs = 2,
> > +	.irq_reg_stride = 2,
> > +	.status_base = RK818_INT_STS_REG1,
> > +	.mask_base = RK818_INT_STS_MSK_REG1,
> > +	.ack_base = RK818_INT_STS_REG1,
> > +	.init_ack_masked = true,
> > +};
> > +
> >  static struct i2c_client *rk808_i2c_client;
> >  static void rk808_device_shutdown(void)
> >  {
> > @@ -167,6 +282,48 @@ static void rk808_device_shutdown(void)
> >  		dev_err(&rk808_i2c_client->dev, "power off error!\n");
> >  }
> >  
> > +static const struct of_device_id rk808_of_match[] = {
> > +	{ .compatible = "rockchip,rk808", .data = (void *) RK808_ID },
> > +	{ .compatible = "rockchip,rk818", .data = (void *) RK818_ID },
> > +	{ },
> > +};
> > +MODULE_DEVICE_TABLE(of, rk808_of_match);
> > +
> > +static int rk8xx_match_device(struct rk808 *rk808, struct device *dev)
> > +{
> > +	const struct of_device_id *of_id;
> > +
> > +	of_id = of_match_device(rk808_of_match, dev);
> > +	if (!of_id) {
> > +		dev_err(dev, "Unable to match OF ID\n");
> > +		return -ENODEV;
> > +	}
> > +	rk808->variant = (long) of_id->data;
> > +
> > +	switch (rk808->variant) {
> > +	case RK808_ID:
> > +		rk808->nr_cells = ARRAY_SIZE(rk808s);
> > +		rk808->cells = rk808s;
> > +		rk808->regmap_cfg = &rk808_regmap_config;
> > +		rk808->regmap_irq_chip = &rk808_irq_chip;
> > +		rk808->pre_init_reg = rk808_pre_init_reg;
> > +		rk808->nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
> > +		break;
> > +	case RK818_ID:
> > +		rk808->nr_cells = ARRAY_SIZE(rk818s);
> > +		rk808->cells = rk818s;
> > +		rk808->regmap_cfg = &rk818_regmap_config;
> > +		rk808->regmap_irq_chip = &rk818_irq_chip;
> > +		rk808->pre_init_reg = rk818_pre_init_reg;
> > +		rk808->nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
> > +		break;
> > +	default:
> > +		dev_err(dev, "unsupported RK8XX ID %lu\n", rk808->variant);
> > +		return -EINVAL;
> > +	}
> > +
> > +	return 0;
> > +}
> >  static int rk808_probe(struct i2c_client *client,
> >  		       const struct i2c_device_id *id)
> >  {
> > @@ -176,45 +333,51 @@ static int rk808_probe(struct i2c_client *client,
> >  	int ret;
> >  	int i;
> >  
> > -	if (!client->irq) {
> > -		dev_err(&client->dev, "No interrupt support, no core IRQ\n");
> > -		return -EINVAL;
> > -	}
> > -
> >  	rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL);
> >  	if (!rk808)
> >  		return -ENOMEM;
> >  
> > -	rk808->regmap = devm_regmap_init_i2c(client, &rk808_regmap_config);
> > +	ret = rk8xx_match_device(rk808, &client->dev);
> > +	if (ret)
> > +		return ret;
> > +
> > +	rk808->i2c = client;
> > +	i2c_set_clientdata(client, rk808);
> > +
> > +	rk808->regmap = devm_regmap_init_i2c(client, rk808->regmap_cfg);
> >  	if (IS_ERR(rk808->regmap)) {
> >  		dev_err(&client->dev, "regmap initialization failed\n");
> >  		return PTR_ERR(rk808->regmap);
> >  	}
> >  
> > -	for (i = 0; i < ARRAY_SIZE(pre_init_reg); i++) {
> > -		ret = regmap_update_bits(rk808->regmap, pre_init_reg[i].addr,
> > -					 pre_init_reg[i].mask,
> > -					 pre_init_reg[i].value);
> > -		if (ret) {
> > -			dev_err(&client->dev,
> > -				"0x%x write err\n", pre_init_reg[i].addr);
> > -			return ret;
> > -		}
> > +	if (!client->irq) {
> > +		dev_err(&client->dev, "No interrupt support, no core IRQ\n");
> > +		return -EINVAL;
> >  	}
> >  
> >  	ret = regmap_add_irq_chip(rk808->regmap, client->irq,
> >  				  IRQF_ONESHOT, -1,
> > -				  &rk808_irq_chip, &rk808->irq_data);
> > +				  rk808->regmap_irq_chip, &rk808->irq_data);
> >  	if (ret) {
> >  		dev_err(&client->dev, "Failed to add irq_chip %d\n", ret);
> >  		return ret;
> >  	}
> >  
> > -	rk808->i2c = client;
> > -	i2c_set_clientdata(client, rk808);
> > +	for (i = 0; i < rk808->nr_pre_init_regs; i++) {
> > +		ret = regmap_update_bits(rk808->regmap,
> > +					rk808->pre_init_reg[i].addr,
> > +					rk808->pre_init_reg[i].mask,
> > +					rk808->pre_init_reg[i].value);
> > +		if (ret) {
> > +			dev_err(&client->dev,
> > +				"0x%x write err\n",
> > +				rk808->pre_init_reg[i].addr);
> > +			return ret;
> > +		}
> > +	}
> >  
> > -	ret = mfd_add_devices(&client->dev, -1,
> > -			      rk808s, ARRAY_SIZE(rk808s),
> > +	ret = mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
> > +			      rk808->cells, rk808->nr_cells,
> >  			      NULL, 0, regmap_irq_get_domain(rk808->irq_data));
> >  	if (ret) {
> >  		dev_err(&client->dev, "failed to add MFD devices %d\n", ret);
> > @@ -246,14 +409,9 @@ static int rk808_remove(struct i2c_client *client)
> >  	return 0;
> >  }
> >  
> > -static const struct of_device_id rk808_of_match[] = {
> > -	{ .compatible = "rockchip,rk808" },
> > -	{ },
> > -};
> > -MODULE_DEVICE_TABLE(of, rk808_of_match);
> > -
> >  static const struct i2c_device_id rk808_ids[] = {
> >  	{ "rk808" },
> > +	{ "rk818" },
> >  	{ },
> >  };
> >  MODULE_DEVICE_TABLE(i2c, rk808_ids);
> > @@ -273,4 +431,5 @@ module_i2c_driver(rk808_i2c_driver);
> >  MODULE_LICENSE("GPL");
> >  MODULE_AUTHOR("Chris Zhong <zyw at rock-chips.com>");
> >  MODULE_AUTHOR("Zhang Qing <zhangqing at rock-chips.com>");
> > -MODULE_DESCRIPTION("RK808 PMIC driver");
> > +MODULE_AUTHOR("Wadim Egorov <w.egorov at phytec.de>");
> > +MODULE_DESCRIPTION("RK808/RK818 PMIC driver");
> > diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h
> > index 441b6ee..5ce810c 100644
> > --- a/include/linux/mfd/rk808.h
> > +++ b/include/linux/mfd/rk808.h
> > @@ -1,11 +1,15 @@
> >  /*
> > - * rk808.h for Rockchip RK808
> > + * Register definitions for Rockchip's RK808/RK818 PMIC
> >   *
> >   * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
> >   *
> >   * Author: Chris Zhong <zyw at rock-chips.com>
> >   * Author: Zhang Qing <zhangqing at rock-chips.com>
> >   *
> > + * Copyright (C) 2016 PHYTEC Messtechnik GmbH
> > + *
> > + * Author: Wadim Egorov <w.egorov at phytec.de>
> > + *
> >   * This program is free software; you can redistribute it and/or modify it
> >   * under the terms and conditions of the GNU General Public License,
> >   * version 2, as published by the Free Software Foundation.
> > @@ -16,8 +20,8 @@
> >   * more details.
> >   */
> >  
> > -#ifndef __LINUX_REGULATOR_rk808_H
> > -#define __LINUX_REGULATOR_rk808_H
> > +#ifndef __LINUX_REGULATOR_RK808_H
> > +#define __LINUX_REGULATOR_RK808_H
> >  
> >  #include <linux/regulator/machine.h>
> >  #include <linux/regmap.h>
> > @@ -28,7 +32,7 @@
> >  
> >  #define RK808_DCDC1	0 /* (0+RK808_START) */
> >  #define RK808_LDO1	4 /* (4+RK808_START) */
> > -#define RK808_NUM_REGULATORS   14
> > +#define RK808_NUM_REGULATORS	14
> >  
> >  enum rk808_reg {
> >  	RK808_ID_DCDC1,
> > @@ -115,7 +119,92 @@ enum rk808_reg {
> >  #define RK808_INT_STS_MSK_REG2	0x4f
> >  #define RK808_IO_POL_REG	0x50
> >  
> > -/* IRQ Definitions */
> > +/* RK818 */
> > +#define RK818_DCDC1			0
> > +#define RK818_LDO1			4
> > +#define RK818_NUM_REGULATORS		17
> > +
> > +enum rk818_reg {
> > +	RK818_ID_DCDC1,
> > +	RK818_ID_DCDC2,
> > +	RK818_ID_DCDC3,
> > +	RK818_ID_DCDC4,
> > +	RK818_ID_BOOST,
> > +	RK818_ID_LDO1,
> > +	RK818_ID_LDO2,
> > +	RK818_ID_LDO3,
> > +	RK818_ID_LDO4,
> > +	RK818_ID_LDO5,
> > +	RK818_ID_LDO6,
> > +	RK818_ID_LDO7,
> > +	RK818_ID_LDO8,
> > +	RK818_ID_LDO9,
> > +	RK818_ID_SWITCH,
> > +	RK818_ID_HDMI_SWITCH,
> > +	RK818_ID_OTG_SWITCH,
> > +};
> > +
> > +#define RK818_DCDC_EN_REG		0x23
> > +#define RK818_LDO_EN_REG		0x24
> > +#define RK818_SLEEP_SET_OFF_REG1	0x25
> > +#define RK818_SLEEP_SET_OFF_REG2	0x26
> > +#define RK818_DCDC_UV_STS_REG		0x27
> > +#define RK818_DCDC_UV_ACT_REG		0x28
> > +#define RK818_LDO_UV_STS_REG		0x29
> > +#define RK818_LDO_UV_ACT_REG		0x2a
> > +#define RK818_DCDC_PG_REG		0x2b
> > +#define RK818_LDO_PG_REG		0x2c
> > +#define RK818_VOUT_MON_TDB_REG		0x2d
> > +#define RK818_BUCK1_CONFIG_REG		0x2e
> > +#define RK818_BUCK1_ON_VSEL_REG		0x2f
> > +#define RK818_BUCK1_SLP_VSEL_REG	0x30
> > +#define RK818_BUCK2_CONFIG_REG		0x32
> > +#define RK818_BUCK2_ON_VSEL_REG		0x33
> > +#define RK818_BUCK2_SLP_VSEL_REG	0x34
> > +#define RK818_BUCK3_CONFIG_REG		0x36
> > +#define RK818_BUCK4_CONFIG_REG		0x37
> > +#define RK818_BUCK4_ON_VSEL_REG		0x38
> > +#define RK818_BUCK4_SLP_VSEL_REG	0x39
> > +#define RK818_BOOST_CONFIG_REG		0x3a
> > +#define RK818_LDO1_ON_VSEL_REG		0x3b
> > +#define RK818_LDO1_SLP_VSEL_REG		0x3c
> > +#define RK818_LDO2_ON_VSEL_REG		0x3d
> > +#define RK818_LDO2_SLP_VSEL_REG		0x3e
> > +#define RK818_LDO3_ON_VSEL_REG		0x3f
> > +#define RK818_LDO3_SLP_VSEL_REG		0x40
> > +#define RK818_LDO4_ON_VSEL_REG		0x41
> > +#define RK818_LDO4_SLP_VSEL_REG		0x42
> > +#define RK818_LDO5_ON_VSEL_REG		0x43
> > +#define RK818_LDO5_SLP_VSEL_REG		0x44
> > +#define RK818_LDO6_ON_VSEL_REG		0x45
> > +#define RK818_LDO6_SLP_VSEL_REG		0x46
> > +#define RK818_LDO7_ON_VSEL_REG		0x47
> > +#define RK818_LDO7_SLP_VSEL_REG		0x48
> > +#define RK818_LDO8_ON_VSEL_REG		0x49
> > +#define RK818_LDO8_SLP_VSEL_REG		0x4a
> > +#define RK818_BOOST_LDO9_ON_VSEL_REG	0x54
> > +#define RK818_BOOST_LDO9_SLP_VSEL_REG	0x55
> > +#define RK818_DEVCTRL_REG		0x4b
> > +#define RK818_INT_STS_REG1		0X4c
> > +#define RK818_INT_STS_MSK_REG1		0x4d
> > +#define RK818_INT_STS_REG2		0x4e
> > +#define RK818_INT_STS_MSK_REG2		0x4f
> > +#define RK818_IO_POL_REG		0x50
> > +#define RK818_H5V_EN_REG		0x52
> > +#define RK818_SLEEP_SET_OFF_REG3	0x53
> > +#define RK818_BOOST_LDO9_ON_VSEL_REG	0x54
> > +#define RK818_BOOST_LDO9_SLP_VSEL_REG	0x55
> > +#define RK818_BOOST_CTRL_REG		0x56
> > +#define RK818_DCDC_ILMAX		0x90
> > +#define RK818_USB_CTRL_REG		0xa1
> > +
> > +#define RK818_H5V_EN			BIT(0)
> > +#define RK818_REF_RDY_CTRL		BIT(1)
> > +#define RK818_USB_ILIM_SEL_MASK		0xf
> > +#define RK818_USB_ILMIN_2000MA		0x7
> > +#define RK818_USB_CHG_SD_VSEL_MASK	0x70
> > +
> > +/* RK808 IRQ Definitions */
> >  #define RK808_IRQ_VOUT_LO	0
> >  #define RK808_IRQ_VB_LO		1
> >  #define RK808_IRQ_PWRON		2
> > @@ -137,6 +226,43 @@ enum rk808_reg {
> >  #define RK808_IRQ_PLUG_IN_INT_MSK	BIT(0)
> >  #define RK808_IRQ_PLUG_OUT_INT_MSK	BIT(1)
> >  
> > +/* RK818 IRQ Definitions */
> > +#define RK818_IRQ_VOUT_LO	0
> > +#define RK818_IRQ_VB_LO		1
> > +#define RK818_IRQ_PWRON		2
> > +#define RK818_IRQ_PWRON_LP	3
> > +#define RK818_IRQ_HOTDIE	4
> > +#define RK818_IRQ_RTC_ALARM	5
> > +#define RK818_IRQ_RTC_PERIOD	6
> > +#define RK818_IRQ_USB_OV	7
> > +#define RK818_IRQ_PLUG_IN	8
> > +#define RK818_IRQ_PLUG_OUT	9
> > +#define RK818_IRQ_CHG_OK	10
> > +#define RK818_IRQ_CHG_TE	11
> > +#define RK818_IRQ_CHG_TS1	12
> > +#define RK818_IRQ_TS2		13
> > +#define RK818_IRQ_CHG_CVTLIM	14
> > +#define RK818_IRQ_DISCHG_ILIM	7
> > +
> > +#define RK818_IRQ_VOUT_LO_MSK		BIT(0)
> > +#define RK818_IRQ_VB_LO_MSK		BIT(1)
> > +#define RK818_IRQ_PWRON_MSK		BIT(2)
> > +#define RK818_IRQ_PWRON_LP_MSK		BIT(3)
> > +#define RK818_IRQ_HOTDIE_MSK		BIT(4)
> > +#define RK818_IRQ_RTC_ALARM_MSK		BIT(5)
> > +#define RK818_IRQ_RTC_PERIOD_MSK	BIT(6)
> > +#define RK818_IRQ_USB_OV_MSK		BIT(7)
> > +#define RK818_IRQ_PLUG_IN_MSK		BIT(0)
> > +#define RK818_IRQ_PLUG_OUT_MSK		BIT(1)
> > +#define RK818_IRQ_CHG_OK_MSK		BIT(2)
> > +#define RK818_IRQ_CHG_TE_MSK		BIT(3)
> > +#define RK818_IRQ_CHG_TS1_MSK		BIT(4)
> > +#define RK818_IRQ_TS2_MSK		BIT(5)
> > +#define RK818_IRQ_CHG_CVTLIM_MSK	BIT(6)
> > +#define RK818_IRQ_DISCHG_ILIM_MSK	BIT(7)
> > +
> > +#define RK818_NUM_IRQ		16
> > +
> >  #define RK808_VBAT_LOW_2V8	0x00
> >  #define RK808_VBAT_LOW_2V9	0x01
> >  #define RK808_VBAT_LOW_3V0	0x02
> > @@ -191,9 +317,27 @@ enum {
> >  	BOOST_ILMIN_250MA,
> >  };
> >  
> > +enum {
> > +	RK808_ID,
> > +	RK818_ID,
> > +};
> > +
> > +struct rk8xx_reg_data {
> > +	int addr;
> > +	int mask;
> > +	int value;
> > +};
> > +
> >  struct rk808 {
> > -	struct i2c_client *i2c;
> > -	struct regmap_irq_chip_data *irq_data;
> > -	struct regmap *regmap;
> > +	struct i2c_client		*i2c;
> > +	struct regmap_irq_chip_data	*irq_data;
> > +	struct regmap			*regmap;
> > +	long				variant;
> > +	int				nr_cells;
> > +	const struct mfd_cell		*cells;
> > +	const struct regmap_config	*regmap_cfg;
> > +	const struct regmap_irq_chip	*regmap_irq_chip;
> > +	const struct rk8xx_reg_data	*pre_init_reg;
> > +	int				nr_pre_init_regs;
> >  };
> > -#endif /* __LINUX_REGULATOR_rk808_H */
> > +#endif /* __LINUX_REGULATOR_RK808_H */
> 

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog


From shawn.lin at kernel-upstream.org  Tue May 10 01:29:52 2016
From: shawn.lin at kernel-upstream.org (Shawn Lin)
Date: Tue, 10 May 2016 16:29:52 +0800
Subject: [PATCH v2 3/6] mmc: core: implement enhanced strobe support
In-Reply-To: <57307AF6.8030401@intel.com>
References: <1461897751-28810-1-git-send-email-shawn.lin@rock-chips.com>
 <1461898029-28944-1-git-send-email-shawn.lin@rock-chips.com>
 <57307AF6.8030401@intel.com>
Message-ID: <d566fb19-2565-66d8-023a-bd9a7ef987b6@kernel-upstream.org>

On 2016/5/9 19:56, Adrian Hunter wrote:
> On 29/04/16 05:47, Shawn Lin wrote:
>> Controllers use data strobe line to latch data from devices
>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>> introduces enhanced strobe mode for latching cmd response from
>> emmc devices to host controllers. This new feature is optional,
>> so it depends both on device's cap and host's cap to decide
>> whether to use it or not.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>
> Thanks for doing this.  There are a couple of comments below, but generally
> I tend to think you should split out selecting HS400ES as a separate function.
>
>> ---
>>
>> Changes in v2: None
>>
>>  drivers/mmc/core/bus.c   |  3 +-
>>  drivers/mmc/core/mmc.c   | 77 ++++++++++++++++++++++++++++++++++++++++++++----
>>  include/linux/mmc/card.h |  1 +
>>  include/linux/mmc/host.h | 12 ++++++++
>>  include/linux/mmc/mmc.h  |  3 ++
>>  5 files changed, 89 insertions(+), 7 deletions(-)
>>
>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> index 4bc48f1..7e94b9d 100644
>> --- a/drivers/mmc/core/bus.c
>> +++ b/drivers/mmc/core/bus.c
>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>  			mmc_card_ddr52(card) ? "DDR " : "",
>>  			type);
>>  	} else {
>> -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>> +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>  			mmc_hostname(card->host),
>>  			mmc_card_uhs(card) ? "ultra high speed " :
>>  			(mmc_card_hs(card) ? "high speed " : ""),
>>  			mmc_card_hs400(card) ? "HS400 " :
>>  			(mmc_card_hs200(card) ? "HS200 " : ""),
>> +			mmc_card_hs400es(card) ? "Enhanced strobe" : "",
>>  			mmc_card_ddr52(card) ? "DDR " : "",
>>  			uhs_bus_speed_mode, type, card->rca);
>>  	}
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index 28b477d..f45ed10 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -235,6 +235,12 @@ static void mmc_select_card_type(struct mmc_card *card)
>>  		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>>  	}
>>
>> +	if ((caps2 & MMC_CAP2_HS400_ENHANCED_STROBE) &&
>> +	    card->ext_csd.strobe_support &&
>> +	    ((card_type & EXT_CSD_CARD_TYPE_HS400_1_2V) ||
>> +	     (card_type & EXT_CSD_CARD_TYPE_HS400_1_8V)))
>
> Could use just "card_type & EXT_CSD_CARD_TYPE_HS400" here

okay, EXT_CSD_CARD_TYPE_HS400 contains 1_2V & 1_8V, so I will
use it.

>
>> +		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
>> +
>>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>>  	card->mmc_avail_type = avail_type;
>> @@ -383,6 +389,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>  			mmc_card_set_blockaddr(card);
>>  	}
>>
>> +	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>>  	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>  	mmc_select_card_type(card);
>>
>> @@ -1062,9 +1069,10 @@ static int mmc_select_hs400(struct mmc_card *card)
>>  	u8 val;
>>
>>  	/*
>> -	 * HS400 mode requires 8-bit bus width
>> +	 * HS400(ES) mode requires 8-bit bus width
>>  	 */
>> -	if (!(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400 &&
>> +	if (!(((card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400) ||
>> +		(card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)) &&
>>  	      host->ios.bus_width == MMC_BUS_WIDTH_8))
>>  		return 0;
>>
>> @@ -1097,9 +1105,26 @@ static int mmc_select_hs400(struct mmc_card *card)
>>  	}
>>
>>  	/* Switch card to DDR */
>> +	val = EXT_CSD_DDR_BUS_WIDTH_8;
>> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
>> +		val |= EXT_CSD_BUS_WIDTH_STROBE;
>> +		/*
>> +		* Make sure we are in non-enhanced strobe mode before we
>> +		* actually enable it in ext_csd.
>> +		*/
>> +		if (host->ops->prepare_enhanced_strobe)
>> +			err = host->ops->prepare_enhanced_strobe(host, false);
>> +
>> +		if (err) {
>> +			pr_err("%s: unprepare_enhanced strobe failed, err:%d\n",
>> +				mmc_hostname(host), err);
>> +			return err;
>> +		}
>> +	}
>> +
>>  	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>  			 EXT_CSD_BUS_WIDTH,
>> -			 EXT_CSD_DDR_BUS_WIDTH_8,
>> +			 val,
>>  			 card->ext_csd.generic_cmd6_time);
>>  	if (err) {
>>  		pr_err("%s: switch to bus width for hs400 failed, err:%d\n",
>> @@ -1124,6 +1149,35 @@ static int mmc_select_hs400(struct mmc_card *card)
>>  	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>>  	mmc_set_bus_speed(card);
>>
>> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
>> +		/* Controller enable enhanced strobe function */
>> +		if (host->ops->prepare_enhanced_strobe)
>> +			err = host->ops->prepare_enhanced_strobe(host, true);
>> +
>> +		if (err) {
>> +			pr_err("%s: prepare enhanced strobe failed, err:%d\n",
>> +				mmc_hostname(host), err);
>> +			return err;
>> +		}
>> +
>> +		/*
>> +		 * After switching to hs400 enhanced strobe mode, we expect to
>> +		 * verify whether it works or not. If controller can't handle
>> +		 * bus width test, compare ext_csd previously read in 1 bit mode
>> +		 * against ext_csd at new bus width
>> +		 */
>
> I don't think we need this.  Just checking (host->caps & MMC_CAP_8_BIT_DATA)
> ought to be enough.  But if you want to play if safe, you could use
> mmc_select_bus_width() in advance.

Ulf also questioned the requirment of doing this.
I consider droping this checking for the next version.

>
>> +		if (!(host->caps & MMC_CAP_BUS_WIDTH_TEST))
>> +			err = mmc_compare_ext_csds(card, MMC_BUS_WIDTH_8);
>> +		else
>> +			err = mmc_bus_test(card, MMC_BUS_WIDTH_8);
>> +
>> +		if (err) {
>> +			pr_warn("%s: switch to enhanced strobe failed\n",
>> +				mmc_hostname(host));
>> +			return err;
>> +		}
>> +	}
>> +
>>  	if (!send_status) {
>>  		err = mmc_switch_status(card);
>>  		if (err)
>> @@ -1297,7 +1351,8 @@ err:
>>  }
>>
>>  /*
>> - * Activate High Speed or HS200 mode if supported.
>> + * Activate High Speed or HS200 mode if supported. For HS400
>> + * with enhanced strobe mode, we should activate High Speed.
>>   */
>>  static int mmc_select_timing(struct mmc_card *card)
>>  {
>> @@ -1306,7 +1361,9 @@ static int mmc_select_timing(struct mmc_card *card)
>>  	if (!mmc_can_ext_csd(card))
>>  		goto bus_speed;
>>
>> -	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
>> +		err = mmc_select_hs(card);
>
> In my view, you should just make a new function: mmc_select_hs400es()

I will spilt a new function to handle the hs400es timing slection.

>
>> +	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>  		err = mmc_select_hs200(card);
>>  	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>  		err = mmc_select_hs(card);
>> @@ -1578,7 +1635,15 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
>>  	} else if (mmc_card_hs(card)) {
>>  		/* Select the desired bus width optionally */
>>  		err = mmc_select_bus_width(card);
>> -		if (!IS_ERR_VALUE(err)) {
>> +		if (IS_ERR_VALUE(err))
>> +			goto free_card;
>> +
>> +		if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES) {
>> +			/* Directly from HS to HS400-ES */
>> +			err = mmc_select_hs400(card);
>> +			if (err)
>> +				goto free_card;
>> +		} else {
>>  			err = mmc_select_hs_ddr(card);
>>  			if (err)
>>  				goto free_card;
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index eb0151b..22defc2 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>>  	u8			raw_partition_support;	/* 160 */
>>  	u8			raw_rpmb_size_mult;	/* 168 */
>>  	u8			raw_erased_mem_count;	/* 181 */
>> +	u8			strobe_support;		/* 184 */
>>  	u8			raw_ext_csd_structure;	/* 194 */
>>  	u8			raw_card_type;		/* 196 */
>>  	u8			raw_driver_strength;	/* 197 */
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index 11e89d3..19de56c 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -19,6 +19,7 @@
>>
>>  #include <linux/mmc/core.h>
>>  #include <linux/mmc/card.h>
>> +#include <linux/mmc/mmc.h>
>>  #include <linux/mmc/pm.h>
>>
>>  struct mmc_ios {
>> @@ -143,6 +144,8 @@ struct mmc_host_ops {
>>
>>  	/* Prepare HS400 target operating frequency depending host driver */
>>  	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>> +	/* Prepare enhanced strobe depending host driver */
>> +	int	(*prepare_enhanced_strobe)(struct mmc_host *host, bool enable);
>
> I don't see any need for an error return, so maybe make this return void.
> Also, we could put "bool enhanced_strobe" in struct mmc_ios and pass ios
> instead of enable.

yep, currently there's no need to check it.
I will change the name to hs400_enhacned_strobe as Ulf's suggestion,
and pass mmc_ios to this callback as well.

>
>>  	int	(*select_drive_strength)(struct mmc_card *card,
>>  					 unsigned int max_dtr, int host_drv,
>>  					 int card_drv, int *drv_type);
>> @@ -518,6 +521,15 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>>  	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>>  }
>>
>> +static inline bool mmc_card_hs400es(struct mmc_card *card)
>> +{
>> +	if (mmc_card_hs400(card) &&
>> +	    (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES))
>> +		return 1;
>
> We shouldn't assume that we are using it, just because it is available.
> How about putting "bool enhanced_strobe" in struct mmc_ios and checking that.
>

Good catch. Thanks.

>> +
>> +	return 0;
>> +}
>> +
>>  void mmc_retune_timer_stop(struct mmc_host *host);
>>
>>  static inline void mmc_retune_needed(struct mmc_host *host)
>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> index 15f2c4a..c376209 100644
>> --- a/include/linux/mmc/mmc.h
>> +++ b/include/linux/mmc/mmc.h
>> @@ -297,6 +297,7 @@ struct _mmc_csd {
>>  #define EXT_CSD_PART_CONFIG		179	/* R/W */
>>  #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
>>  #define EXT_CSD_BUS_WIDTH		183	/* R/W */
>> +#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
>>  #define EXT_CSD_HS_TIMING		185	/* R/W */
>>  #define EXT_CSD_POWER_CLASS		187	/* R/W */
>>  #define EXT_CSD_REV			192	/* RO */
>> @@ -380,12 +381,14 @@ struct _mmc_csd {
>>  #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
>>  #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
>>  					 EXT_CSD_CARD_TYPE_HS400_1_2V)
>> +#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
>>
>>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
>>  #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
>>  #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
>>
>>  #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
>>  #define EXT_CSD_TIMING_HS	1	/* High speed */
>>
>
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>



From shawn.lin at rock-chips.com  Tue May 10 02:09:03 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 10 May 2016 17:09:03 +0800
Subject: [PATCH v3 0/5] Add enhanced strobe support for emmc version 5.1 or
 later
Message-ID: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>


Hello Ulf and Adrian,

This patch is going to support enhanced strobe function
for emmc version 5.1+ introduced by JEDEC recently.

Enchanced strobe is a optional function, so we add a new cap* for drivers to
decide whether to use it.

When introduing hs400 mode, JEDEC asks controllers to use data strobe line
to latch the data from emmc devives. But for cmd-reponse, not mentioned yet.
Since emmc version 5.1 published, JEDEC adds enhanced strobe function to deal
with cmd-response the same way as data-read. This feature is optional.

>From the spec(section 6.6.2.3), the standard scenario to select HS400 enhanced
strobe mode illustrated like this:
(1) set HS_TIMIMG (Highspeed)
(2) Host change freq to <= 52Mhz
(3) set the bus width to Enhanced strobe and DDR8Bit(CMD6), EXT_CSD[183] = 0x86
instead of 0x80
(4) set HS_TIMING to 0x3 (HS400)
(5) Host change freq to <= 200Mhz
(6) Host select HS400 enhanced strobe complete

I can't find a upstreamed controller claimed to support it, as well as the
mmc stack. But my "arasan,sdhci-5.1" actually supports this function. So I decide
to work for this part.

By looking into the SDHCI spec, I find there isn't any registers to enable the
enhanced strobe function. But from my "arasan,sdhci-5.1" databook, it describes a
register called VENDOR_REGISTER(0x78) to trigger this mode. So I guess other sdhci
variant drivers may also need s vendor specific register to deal with it.

If we are sure that our controller supports enhanced strobe mode, just add
mmc-hs400-enhanced-strobe in DT. Once emmc devices claims to support this mode,
we enable it automatically. Of course, other sdhci*/non-sdhci drivers should
implement/overwrite the prepare_enhanced_strobe by themselves. I believe all of the
platforms which need to support this mode should do some basic preparation for their
controllers. Currently I just limit the callback within ths scope of arasan,sdhci-5.1,
but I prone to believe arasan will use VENDOR_REGISTER to tirgger this mode from now on
because I do believe vendor will consider the registers' compatibility.

With this patchset applied, we can successfully run in HS400 enhanced strobe mode on
RK3399 platform with Samsung eMMC KLMBG2JENB-B041(v5.1, 16GB).

mmc1: new HS400 Enhanced strobe MMC card at address 0001
mmcblk0: mmc1:0001 AJNB4R 14.6 GiB
mmcblk0boot0: mmc1:0001 AJNB4R partition 1 4.00 MiB
mmcblk0boot1: mmc1:0001 AJNB4R partition 2 4.00 MiB
mmcblk0rpmb: mmc1:0001 AJNB4R partition 3 4.00 MiB

Also I check this patchset with removing some caps to make sure
all the init sequences for hs400/hs200/DDR52/HighSpeed is correct.


Changes in v3:
- remove helper function and shorten cap2 to MMC_CAP2_HS400_ES
- rename callback to hs400_enhanced_strobe and make it return void
- add enhanced_strobe in mmc_ios and pass it to hs400_enhanced_strobe
- disable host's enhanced strobe in mmc_set_initial_state
- remove bus checking after switching hs400es
- add new function for hs400es timing selection
- fix wrong judgement of mmc_card_hs400es

Changes in v2:
- switch to HS400ES from Highspeed mode directly

Shawn Lin (5):
  Documentation: mmc: add mmc-hs400-enhanced-strobe
  mmc: core: add mmc-hs400-enhanced-strobe support
  mmc: core: implement enhanced strobe support
  mmc: debugfs: add HS400 enhanced strobe description
  mmc: sdhci-of-arasan: implement enhanced strobe callback

 Documentation/devicetree/bindings/mmc/mmc.txt |  1 +
 drivers/mmc/core/bus.c                        |  3 +-
 drivers/mmc/core/core.c                       |  8 +++
 drivers/mmc/core/debugfs.c                    |  4 +-
 drivers/mmc/core/host.c                       |  2 +
 drivers/mmc/core/mmc.c                        | 79 ++++++++++++++++++++++++++-
 drivers/mmc/host/sdhci-of-arasan.c            | 20 +++++++
 include/linux/mmc/card.h                      |  1 +
 include/linux/mmc/host.h                      | 12 ++++
 include/linux/mmc/mmc.h                       |  3 +
 10 files changed, 129 insertions(+), 4 deletions(-)

-- 
2.3.7




From shawn.lin at rock-chips.com  Tue May 10 02:09:35 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 10 May 2016 17:09:35 +0800
Subject: [PATCH v3 1/5] Documentation: mmc: add mmc-hs400-enhanced-strobe
In-Reply-To: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1462871375-32402-1-git-send-email-shawn.lin@rock-chips.com>

mmc-hs400-enhanced-strobe is used to claim that the
host can support hs400 mode with enhanced strobe
introduced by emmc 5.1 spec.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
Acked-by: Rob Herring <robh at kernel.org>
---

Changes in v3: None
Changes in v2: None

 Documentation/devicetree/bindings/mmc/mmc.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index ed23b9b..ecc007a 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -46,6 +46,7 @@ Optional properties:
 - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
 - mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
 - mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
+- mmc-hs400-enhanced-strobe: eMMC HS400 enhanced strobe mode is supported
 - dsr: Value the card's (optional) Driver Stage Register (DSR) should be
   programmed with. Valid range: [0 .. 0xffff].
 
-- 
2.3.7




From shawn.lin at rock-chips.com  Tue May 10 02:09:43 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 10 May 2016 17:09:43 +0800
Subject: [PATCH v3 2/5] mmc: core: add mmc-hs400-enhanced-strobe support
In-Reply-To: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1462871383-32443-1-git-send-email-shawn.lin@rock-chips.com>

This patch introduce mmc-hs400-enhanced-strobe for platforms
which want to enable enhanced strobe function from DT if the
mmc host controller claims to support enhanced strobe.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

---

Changes in v3:
- remove helper function and shorten cap2 to MMC_CAP2_HS400_ES
- rename callback to hs400_enhanced_strobe and make it return void
- add enhanced_strobe in mmc_ios and pass it to hs400_enhanced_strobe
- disable host's enhanced strobe in mmc_set_initial_state
- remove bus checking after switching hs400es
- add new function for hs400es timing selection
- fix wrong judgement of mmc_card_hs400es

Changes in v2:
- switch to HS400ES from Highspeed mode directly

 drivers/mmc/core/host.c  | 2 ++
 include/linux/mmc/host.h | 1 +
 2 files changed, 3 insertions(+)

diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index e0a3ee1..45773e4 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -289,6 +289,8 @@ int mmc_of_parse(struct mmc_host *host)
 		host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
 	if (of_property_read_bool(np, "mmc-hs400-1_2v"))
 		host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
+	if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
+		host->caps2 |= MMC_CAP2_HS400_ES;
 
 	host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
 	if (host->dsr_req && (host->dsr & ~0xffff)) {
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 85800b4..2a06fb0 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -302,6 +302,7 @@ struct mmc_host {
 #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
 #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18)	/* No physical write protect pin, assume that card is always read-write */
 #define MMC_CAP2_NO_SDIO	(1 << 19)	/* Do not send SDIO commands during initialization */
+#define MMC_CAP2_HS400_ES	(1 << 20)	/* Host supports enhanced strobe */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
-- 
2.3.7




From shawn.lin at rock-chips.com  Tue May 10 02:09:51 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 10 May 2016 17:09:51 +0800
Subject: [PATCH v3 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1462871391-32484-1-git-send-email-shawn.lin@rock-chips.com>

Controllers use data strobe line to latch data from devices
under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
introduces enhanced strobe mode for latching cmd response from
emmc devices to host controllers. This new feature is optional,
so it depends both on device's cap and host's cap to decide
whether to use it or not.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

Changes in v3: None
Changes in v2: None

 drivers/mmc/core/bus.c   |  3 +-
 drivers/mmc/core/core.c  |  8 +++++
 drivers/mmc/core/mmc.c   | 79 ++++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/mmc/card.h |  1 +
 include/linux/mmc/host.h | 11 +++++++
 include/linux/mmc/mmc.h  |  3 ++
 6 files changed, 102 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 4bc48f1..7e94b9d 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
-		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
+		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
 			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
+			mmc_card_hs400es(card) ? "Enhanced strobe" : "",
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 99275e4..a559501 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1127,6 +1127,14 @@ void mmc_set_initial_state(struct mmc_host *host)
 	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ios.timing = MMC_TIMING_LEGACY;
 	host->ios.drv_type = 0;
+	host->ios.enhanced_strobe = false;
+
+	/*
+	 * Make sure we are in non-enhanced strobe mode before we
+	 * actually enable it in ext_csd.
+	 */
+	if (host->ops->hs400_enhanced_strobe)
+		host->ops->hs400_enhanced_strobe(host, &host->ios);
 
 	mmc_set_ios(host);
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f99c47e..c2d1981 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
 	}
 
+	if ((caps2 & MMC_CAP2_HS400_ES) &&
+	    card->ext_csd.strobe_support &&
+	    (card_type & EXT_CSD_CARD_TYPE_HS400))
+		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			mmc_card_set_blockaddr(card);
 	}
 
+	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
 	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
 	mmc_select_card_type(card);
 
@@ -1216,6 +1222,73 @@ out_err:
 	return err;
 }
 
+static int mmc_select_hs400es(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+	u8 val;
+
+	err = mmc_select_bus_width(card);
+	if (IS_ERR_VALUE(err))
+		goto out_err;
+
+	/* Switch card to HS mode */
+	err = mmc_select_hs(card);
+	if (err) {
+		pr_err("%s: switch to high-speed failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	err = mmc_switch_status(card);
+	if (err)
+		goto out_err;
+
+	/* Switch card to DDR with strobe bit */
+	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 val,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	/* Switch card to HS400 */
+	val = EXT_CSD_TIMING_HS400 |
+	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, val,
+			   card->ext_csd.generic_cmd6_time,
+			   true, false, true);
+	if (err) {
+		pr_err("%s: switch to hs400es failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	/* Set host controller to HS400 timing and frequency */
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+
+	/* Controller enable enhanced strobe function */
+	host->ios.enhanced_strobe = true;
+	if (host->ops->hs400_enhanced_strobe)
+		host->ops->hs400_enhanced_strobe(host, &host->ios);
+
+	err = mmc_switch_status(card);
+	if (err)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
+	       __func__, err);
+	return err;
+}
+
 static void mmc_select_driver_type(struct mmc_card *card)
 {
 	int card_drv_type, drive_strength, drv_type;
@@ -1297,7 +1370,7 @@ err:
 }
 
 /*
- * Activate High Speed or HS200 mode if supported.
+ * Activate High Speed, HS200 or HS400ES mode if supported.
  */
 static int mmc_select_timing(struct mmc_card *card)
 {
@@ -1306,7 +1379,9 @@ static int mmc_select_timing(struct mmc_card *card)
 	if (!mmc_can_ext_csd(card))
 		goto bus_speed;
 
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
+		err = mmc_select_hs400es(card);
+	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 		err = mmc_select_hs200(card);
 	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 		err = mmc_select_hs(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index eb0151b..22defc2 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -95,6 +95,7 @@ struct mmc_ext_csd {
 	u8			raw_partition_support;	/* 160 */
 	u8			raw_rpmb_size_mult;	/* 168 */
 	u8			raw_erased_mem_count;	/* 181 */
+	u8			strobe_support;		/* 184 */
 	u8			raw_ext_csd_structure;	/* 194 */
 	u8			raw_card_type;		/* 196 */
 	u8			raw_driver_strength;	/* 197 */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2a06fb0..f98bd0e 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -19,6 +19,7 @@
 
 #include <linux/mmc/core.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -77,6 +78,8 @@ struct mmc_ios {
 #define MMC_SET_DRIVER_TYPE_A	1
 #define MMC_SET_DRIVER_TYPE_C	2
 #define MMC_SET_DRIVER_TYPE_D	3
+
+	bool enhanced_strobe;			/* hs400es selection */
 };
 
 struct mmc_host_ops {
@@ -143,6 +146,9 @@ struct mmc_host_ops {
 
 	/* Prepare HS400 target operating frequency depending host driver */
 	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
+	/* Prepare enhanced strobe depending host driver */
+	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
+					 struct mmc_ios *ios);
 	int	(*select_drive_strength)(struct mmc_card *card,
 					 unsigned int max_dtr, int host_drv,
 					 int card_drv, int *drv_type);
@@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
 	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
 }
 
+static inline bool mmc_card_hs400es(struct mmc_card *card)
+{
+	return card->host->ios.enhanced_strobe == true;
+}
+
 void mmc_retune_timer_stop(struct mmc_host *host);
 
 static inline void mmc_retune_needed(struct mmc_host *host)
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 15f2c4a..c376209 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -297,6 +297,7 @@ struct _mmc_csd {
 #define EXT_CSD_PART_CONFIG		179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
+#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
 #define EXT_CSD_POWER_CLASS		187	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
@@ -380,12 +381,14 @@ struct _mmc_csd {
 #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
 #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
 					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
 #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
 #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
+#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
 
 #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
 #define EXT_CSD_TIMING_HS	1	/* High speed */
-- 
2.3.7




From shawn.lin at rock-chips.com  Tue May 10 02:09:59 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 10 May 2016 17:09:59 +0800
Subject: [PATCH v3 4/5] mmc: debugfs: add HS400 enhanced strobe description
In-Reply-To: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1462871399-32525-1-git-send-email-shawn.lin@rock-chips.com>

We introduce HS400 with enhanced strobe function, so we need
to add it for debug show.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

Changes in v3: None
Changes in v2: None

 drivers/mmc/core/debugfs.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 9382a57..51d7c38 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -148,7 +148,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc HS200";
 		break;
 	case MMC_TIMING_MMC_HS400:
-		str = "mmc HS400";
+		mmc_card_hs400es(host->card) ?
+			(str = "mmc HS400 enhanced strobe") :
+			(str = "mmc HS400");
 		break;
 	default:
 		str = "invalid";
-- 
2.3.7




From shawn.lin at rock-chips.com  Tue May 10 02:10:07 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 10 May 2016 17:10:07 +0800
Subject: [PATCH v3 5/5] mmc: sdhci-of-arasan: implement enhanced strobe
 callback
In-Reply-To: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1462871407-32566-1-git-send-email-shawn.lin@rock-chips.com>

Currently sdhci-arasan 5.1 can support enhanced strobe function,
and we now limit it just for "arasan,sdhci-5.1". Add
mmc-hs400-enhanced-strobe in DT to enable the function if we'r sure
our controller can support it.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

Changes in v3: None
Changes in v2: None

 drivers/mmc/host/sdhci-of-arasan.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index b6f4c1d..8e5cb06 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -25,7 +25,9 @@
 #include "sdhci-pltfm.h"
 
 #define SDHCI_ARASAN_CLK_CTRL_OFFSET	0x2c
+#define SDHCI_ARASAN_VENDOR_REGISTER	0x78
 
+#define VENDOR_ENHANCED_STROBE		BIT(0)
 #define CLK_CTRL_TIMEOUT_SHIFT		16
 #define CLK_CTRL_TIMEOUT_MASK		(0xf << CLK_CTRL_TIMEOUT_SHIFT)
 #define CLK_CTRL_TIMEOUT_MIN_EXP	13
@@ -79,6 +81,21 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
 	}
 }
 
+static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
+					struct mmc_ios *ios)
+{
+	u32 vendor;
+	struct sdhci_host *host = mmc_priv(mmc);
+
+	vendor = readl(host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
+	if (ios->enhanced_strobe)
+		vendor |= VENDOR_ENHANCED_STROBE;
+	else
+		vendor &= (~VENDOR_ENHANCED_STROBE);
+
+	writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
+}
+
 static struct sdhci_ops sdhci_arasan_ops = {
 	.set_clock = sdhci_arasan_set_clock,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
@@ -245,6 +262,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev, "phy_power_on err.\n");
 			goto err_phy_power;
 		}
+
+		host->mmc_host_ops.hs400_enhanced_strobe =
+					sdhci_arasan_hs400_enhanced_strobe;
 	}
 
 	ret = sdhci_add_host(host);
-- 
2.3.7




From shawn.lin at rock-chips.com  Tue May 10 03:19:49 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 10 May 2016 18:19:49 +0800
Subject: [PATCH 2/2] dt-bindings: rockchip-dw-mshc: add
 rockchip,default-drv-phase
In-Reply-To: <CAD=FV=XToSzqSh=SShHuQU9W_m7gfyQn8wRXkLy79t+tnqZknA@mail.gmail.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
 <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=WSkBwBjVsRoDsfjD+sNfR70mKGRA0khjPKKW0zS2=PTw@mail.gmail.com>
 <b15dcb4f-1584-8219-2fe0-97eecb0c64a6@rock-chips.com>
 <CAD=FV=XToSzqSh=SShHuQU9W_m7gfyQn8wRXkLy79t+tnqZknA@mail.gmail.com>
Message-ID: <1f2f43c7-2672-e448-eddb-2d613bb8dc48@rock-chips.com>

? 2016/5/10 0:31, Doug Anderson ??:
> Hi,
>
> On Mon, May 9, 2016 at 4:12 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>> 1. Specifying a single number for this property in terms of "degrees"
>>> is probably not right.  The whole point of setting the "drive phase"
>>> is to meet hold times, which are specified in the spec in terms of ns
>>> in the spec and also specified differently for different SD/MMC speed
>>> modes.  Note also that "phase" translates to very different delays (in
>>> terms of ns) depending on the clock rate:
>>>
>>> At 400 kHz, period is 2.5 us, so 90 degree phase offset is a delay of 625
>>> ns
>>> At 25 MHz, period is 40 ns, so a 90 degree phase offset represents a
>>> delay of 10 ns.
>>> At 50 MHz, period is 20 ns, so a 90 degree phase offset represents a
>>> delay of 5 ns.
>>> At 200 MHz, period is period is 5 ns, so a 90 degree phase offset
>>> represents a delay of 1.25 ns.
>>
>>
>> yes, if we use degrees only(0/90/180/270), the timing is always right.
>> But considering the delay number, we need to do some crazy calculation
>> in the set_ios callback.
>
> Great, so let's limit it to 0/90/180/270 for the drive phase offset.
> We don't need lots of precision for the drive phase offset (right?)
> and accuracy is more important.

yes.

>
>
>>> 2. As I understand it, the value needed for the drive phase is not
>>> board specific unless you've got super crazy layout on a board (where
>>> the clock line takes a very different path than everything else).
>>> It's also not even terribly SoC-specific unless you've got some very
>>> strange incarnation of dw_mmc that has very different internal delays
>>> than everyone else.  Said another way, until we see an instance of an
>>> SoC/board that really needs to do things special I'd say that we
>>> should just implement this all in code (no device tree bindings).
>>>
>>
>> I'm prone to think it should be Soc specific if making sure the layout
>> for data lines is in equal length.
>
> Sure, it can be SoC specific.  ...though at the moment, I'd bet that
> you can come up with a single rule for the drive phase offset that
> will work for every Rockchip SoC produced so far, especially if you
> are using only 0/90/180/270.  I'd imagine that they all have similar
> enough internal delays.

For a specific Soc, it's the basic rule to make sure the internal delays
is the same(nearly the same) for all of the lines.

>
>
>>> 3. If this property was actually board specific and actually needed to
>>> be tuned board-by-board, you'd have a bug because your new device tree
>>> bindings are not backward compatible and you'd probably be breaking
>>> old boards.  Specifically you're changing the definition of what
>>> happens when "rockchip,default-drv-phase" is not specified.  Old
>>> behavior was to leave the value that was setup by the firmware (or
>>> perhaps the hardware default if the firmware didn't touch this).
>>
>>
>> drv_phase is for all the data lines instead of tuning the lines
>> one-by-one. So this patch can't save the terrible board layout.
>> But I agree that it will break the compatibility backward if firware
>> touch this value.
>>
>>>
>>> ---
>>>
>>> OK, so what should we do?
>>>
>>> We could certainly do lots of crazy math to come up with the ideal
>>> hold time for all different speed modes and all different types of
>>> cards.  With my reading of the Designware Databook this would mean
>>> that somewhere we'd want to specify which delay method we're using
>>> (phase shift vs. delay line) and how long all the delays timings all
>>> are on your particular SoC.  That all sounds quite difficult, though.
>>
>>
>> delay line is diff from chip to chip, soc-to-soc, board-to-board. For
>> sample-phase we have tuning process and re-tune, but not for drv-phase.
>> So We bascially should avoid to use it for drv-phase. Another
>> consideration is the temperature drift of delay line.
>>
>> Maybe we should do some tricky limitation on clk-mmc-phase to only
>> support fixed degrees?
>
> As per above, let's not use delay line for drive delay.  On all
> Rockchip SoCs that I have seen it's possible to make 0/90/180/270 very
> accurately.  That means no board-to-board differences.  Current
> mainline Linux kernel source code will always make 0/90/180/270 using
> phase offset (not delay line).

yes, 0/90/180/270 is very accurate and mainline kernel use phase offset
for these four phase.

>
> For sampling we use tuning and using the delay elements makes some
> sense (since 90 degrees is not quite accurate enough to fully tune
> UHS).  ...but for driving where the only requirement is hold times we
> don't need delay elements.

Right. We care hold time here.

>
>
>>> Probably you could just add a simple function that looked at the clock
>>> and speed mode and always chose an offset of 90 or 180 degrees.  At
>>> least on Rockchip devices you can be certain that you can make 90 and
>>> 180 degrees using phase shifts and thus the timings should be
>>> consistent.  By default you could just always choose 180.  The
>>> Designware databook has some examples where it picked 90 degrees
>>> (SDR50, DDR50, SDR25, MMC High Speed), but I'm not enough of an MMC
>>> expert to know if there is some benefit to choosing 90.  Would we
>>> violate any specs if we just chose 180 degrees all the time everywhere
>>> on all Rockchip devices?
>>
>>
>> It needs more waveform test to see how things going. But most of
>> rockchip platforms in the pass years didn't touch drv-phase stuff not
>> only in kernel but also in firmware, then we still cannot see the
>> violation against the spec when using defalut reset value, namely 180, for
>> drv-phase.
>
> Right, most Rockchip platforms simply don't touch this and it works
> OK.  ...but I don't think it defaults to 180.  Grepping through on my
> veyron (rk3288) device shows
>
>        sdio1_drv - 90
>        sdio0_drv - 90
>        sdmmc_drv - 90
>        emmc_drv -180
>
> ...and, as we've seen, these values appear to be 270 on some other SoCs.
>

Have your code touched them? I check the TRM and find it should be 180
always.

Also for rk3036/3368/3399/3228.... the reset vaule is 180...

>
> The claim from the Designware Databook says that SDR104 and SDR12, and
> identification mode need 180 degrees to work properly.  It would be
> interesting to hook up rk3288 to a signal analyzer and see hold times
> are OK or if we need to move up to 180 degrees for those modes.
>
> Note that the Designware Databook assumes "Delay_O" of 1.4ns.  If
> yours is shorter then maybe 90 degrees is OK for those modes?
>

maybe. But I think 180(downside) is the better.

>
> Also: I still haven't heard whether there is any downside to using 180
> degrees for modes that only require 90 degrees.  Does it cause
> problems to just always use 180 degrees?  If not, we could possibly
> use 180 degrees everywhere and just hardcode it?

 From tons of test on rockchip products which always use 180, I didn't
see failure. Hardcoding it doesn't look so decent maybe... but anyway
it works.

>
>
> ...but if 180 is ideal everywhere, can you answer:
>
> * Why does dw_mmc manual spend so much time talking about it?  It
> could just say "set to 180 degrees".

I'm sure all the rockchip Socs defaultly use 180 for drv_phase if I got
the right TRMs these years.

Anyway let me check it with my ASIC team and I will let you know
the result.


Thanks.

>
> * Why do Rockchip SoCs default to values that are not 180 degrees?
>
> -Doug
>
>
>


-- 
Best Regards
Shawn Lin



From wxt at rock-chips.com  Tue May 10 04:14:56 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Tue, 10 May 2016 19:14:56 +0800
Subject: [PATCH] pinctrl: rockchip: fix pull setting error for rk3399
Message-ID: <1462878896-28956-1-git-send-email-wxt@rock-chips.com>

From: David Wu <david.wu at rock-chips.com>

This patch fixes the pinctrl pull bias setting, since the pull up/down
setting is the contrary for gpio0.

>From the TRM said, the gpio0 pull polarity setting:
gpio0a_p (gpio0 )
GPIO0A PE/PS programmation section, every
GPIO bit corresponding to 2bits[PS:PE]
2'b00: Z(Noraml operaton);
2'b11: weak 1(pull-up);
2'b01: weak 0(pull-down);
2'b10: Z(Noraml operaton);

Then, the other gpios setting as the following:
gpio1a_p (gpio1, gpio2, gpio3...)
GPIO1A PU/PD programmation section, every
GPIO bit corresponding to 2bits
2'b00: Z(Noraml operaton);
2'b01: weak 1(pull-up);
2'b10: weak 0(pull-down);
2'b11: Repeater(Bus keeper)

For example,(rk3399evb board)
sdmmc_cd --->gpio0_a7
localhost / # io -r -4 0xff320040
ff320040: 00004d5f
In general,the value should be 0x0000cd5f since the pin set in the dts.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Linus Walleij <linus.walleij at linaro.org>
Cc: Heiko Stuebner <heiko at sntech.de>
Cc: linux-gpio at vger.kernel.org
---

 drivers/pinctrl/pinctrl-rockchip.c | 178 ++++++++++++++++++++++++++-----------
 1 file changed, 126 insertions(+), 52 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 596b869..38be9c7 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -99,6 +99,15 @@ enum rockchip_pin_drv_type {
 };
 
 /**
+ * enum type index corresponding to rockchip_pull_list arrays index.
+ */
+enum rockchip_pin_pull_type {
+	PULL_TYPE_IO_DEFAULT = 0,
+	PULL_TYPE_IO_1V8_ONLY,
+	PULL_TYPE_MAX
+};
+
+/**
  * @drv_type: drive strength variant using rockchip_perpin_drv_type
  * @offset: if initialized to -1 it will be autocalculated, by specifying
  *	    an initial offset value the relevant source offset can be reset
@@ -123,6 +132,7 @@ struct rockchip_drv {
  * @bank_num: number of the bank, to account for holes
  * @iomux: array describing the 4 iomux sources of the bank
  * @drv: array describing the 4 drive strength sources of the bank
+ * @pull_type: array describing the 4 pull type sources of the bank
  * @valid: are all necessary informations present
  * @of_node: dt node of this bank
  * @drvdata: common pinctrl basedata
@@ -143,6 +153,7 @@ struct rockchip_pin_bank {
 	u8				bank_num;
 	struct rockchip_iomux		iomux[4];
 	struct rockchip_drv		drv[4];
+	enum rockchip_pin_pull_type	pull_type[4];
 	bool				valid;
 	struct device_node		*of_node;
 	struct rockchip_pinctrl		*drvdata;
@@ -198,6 +209,31 @@ struct rockchip_pin_bank {
 		},							\
 	}
 
+#define PIN_BANK_DRV_FLAGS_PULL_FLAGS(id, pins, label, drv0, drv1,	\
+				      drv2, drv3, pull0, pull1,		\
+				      pull2, pull3)			\
+	{								\
+		.bank_num	= id,					\
+		.nr_pins	= pins,					\
+		.name		= label,				\
+		.iomux		= {					\
+			{ .offset = -1 },				\
+			{ .offset = -1 },				\
+			{ .offset = -1 },				\
+			{ .offset = -1 },				\
+		},							\
+		.drv		= {					\
+			{ .drv_type = drv0, .offset = -1 },		\
+			{ .drv_type = drv1, .offset = -1 },		\
+			{ .drv_type = drv2, .offset = -1 },		\
+			{ .drv_type = drv3, .offset = -1 },		\
+		},							\
+		.pull_type[0] = pull0,					\
+		.pull_type[1] = pull1,					\
+		.pull_type[2] = pull2,					\
+		.pull_type[3] = pull3,					\
+	}
+
 #define PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(id, pins, label, iom0, iom1,	\
 					iom2, iom3, drv0, drv1, drv2,	\
 					drv3, offset0, offset1,		\
@@ -220,6 +256,34 @@ struct rockchip_pin_bank {
 		},							\
 	}
 
+#define PIN_BANK_IOMUX_FLAGS_DRV_FLAGS_OFFSET_PULL_FLAGS(id, pins,	\
+					      label, iom0, iom1, iom2,  \
+					      iom3, drv0, drv1, drv2,   \
+					      drv3, offset0, offset1,   \
+					      offset2, offset3, pull0,  \
+					      pull1, pull2, pull3)	\
+	{								\
+		.bank_num	= id,					\
+		.nr_pins	= pins,					\
+		.name		= label,				\
+		.iomux		= {					\
+			{ .type = iom0, .offset = -1 },			\
+			{ .type = iom1, .offset = -1 },			\
+			{ .type = iom2, .offset = -1 },			\
+			{ .type = iom3, .offset = -1 },			\
+		},							\
+		.drv		= {					\
+			{ .drv_type = drv0, .offset = offset0 },	\
+			{ .drv_type = drv1, .offset = offset1 },	\
+			{ .drv_type = drv2, .offset = offset2 },	\
+			{ .drv_type = drv3, .offset = offset3 },	\
+		},							\
+		.pull_type[0] = pull0,					\
+		.pull_type[1] = pull1,					\
+		.pull_type[2] = pull2,					\
+		.pull_type[3] = pull3,					\
+	}
+
 /**
  */
 struct rockchip_pin_ctrl {
@@ -1020,12 +1084,27 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
 	return ret;
 }
 
+static int rockchip_pull_list[PULL_TYPE_MAX][4] = {
+	{
+		PIN_CONFIG_BIAS_DISABLE,
+		PIN_CONFIG_BIAS_PULL_UP,
+		PIN_CONFIG_BIAS_PULL_DOWN,
+		PIN_CONFIG_BIAS_BUS_HOLD
+	},
+	{
+		PIN_CONFIG_BIAS_DISABLE,
+		PIN_CONFIG_BIAS_PULL_DOWN,
+		PIN_CONFIG_BIAS_DISABLE,
+		PIN_CONFIG_BIAS_PULL_UP
+	},
+};
+
 static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
 {
 	struct rockchip_pinctrl *info = bank->drvdata;
 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
 	struct regmap *regmap;
-	int reg, ret;
+	int reg, ret, pull_type;
 	u8 bit;
 	u32 data;
 
@@ -1048,22 +1127,11 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
 	case RK3288:
 	case RK3368:
 	case RK3399:
+		pull_type = bank->pull_type[pin_num / 8];
 		data >>= bit;
 		data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1;
 
-		switch (data) {
-		case 0:
-			return PIN_CONFIG_BIAS_DISABLE;
-		case 1:
-			return PIN_CONFIG_BIAS_PULL_UP;
-		case 2:
-			return PIN_CONFIG_BIAS_PULL_DOWN;
-		case 3:
-			return PIN_CONFIG_BIAS_BUS_HOLD;
-		}
-
-		dev_err(info->dev, "unknown pull setting\n");
-		return -EIO;
+		return rockchip_pull_list[pull_type][data];
 	default:
 		dev_err(info->dev, "unsupported pinctrl type\n");
 		return -EINVAL;
@@ -1076,7 +1144,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
 	struct rockchip_pinctrl *info = bank->drvdata;
 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
 	struct regmap *regmap;
-	int reg, ret;
+	int reg, ret, i, pull_type;
 	unsigned long flags;
 	u8 bit;
 	u32 data, rmask;
@@ -1105,30 +1173,27 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
 	case RK3288:
 	case RK3368:
 	case RK3399:
+		pull_type = bank->pull_type[pin_num / 8];
+		ret = -EINVAL;
+		for (i = 0; i < ARRAY_SIZE(rockchip_pull_list[pull_type]);
+			i++) {
+			if (rockchip_pull_list[pull_type][i] == pull) {
+				ret = i;
+				break;
+			}
+		}
+
+		if (ret < 0) {
+			dev_err(info->dev, "unknown pull setting %d\n", pull);
+			return ret;
+		}
+
 		spin_lock_irqsave(&bank->slock, flags);
 
 		/* enable the write to the equivalent lower bits */
 		data = ((1 << RK3188_PULL_BITS_PER_PIN) - 1) << (bit + 16);
 		rmask = data | (data >> 16);
-
-		switch (pull) {
-		case PIN_CONFIG_BIAS_DISABLE:
-			break;
-		case PIN_CONFIG_BIAS_PULL_UP:
-			data |= (1 << bit);
-			break;
-		case PIN_CONFIG_BIAS_PULL_DOWN:
-			data |= (2 << bit);
-			break;
-		case PIN_CONFIG_BIAS_BUS_HOLD:
-			data |= (3 << bit);
-			break;
-		default:
-			spin_unlock_irqrestore(&bank->slock, flags);
-			dev_err(info->dev, "unsupported pull setting %d\n",
-				pull);
-			return -EINVAL;
-		}
+		data |= (ret << bit);
 
 		ret = regmap_update_bits(regmap, reg, rmask, data);
 
@@ -2552,19 +2617,24 @@ static struct rockchip_pin_ctrl rk3368_pin_ctrl = {
 };
 
 static struct rockchip_pin_bank rk3399_pin_banks[] = {
-	PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(0, 32, "gpio0", IOMUX_SOURCE_PMU,
-					IOMUX_SOURCE_PMU,
-					IOMUX_SOURCE_PMU,
-					IOMUX_SOURCE_PMU,
-					DRV_TYPE_IO_1V8_ONLY,
-					DRV_TYPE_IO_1V8_ONLY,
-					DRV_TYPE_IO_DEFAULT,
-					DRV_TYPE_IO_DEFAULT,
-					0x0,
-					0x8,
-					-1,
-					-1
-					),
+	PIN_BANK_IOMUX_FLAGS_DRV_FLAGS_OFFSET_PULL_FLAGS(0, 32, "gpio0",
+							 IOMUX_SOURCE_PMU,
+							 IOMUX_SOURCE_PMU,
+							 IOMUX_SOURCE_PMU,
+							 IOMUX_SOURCE_PMU,
+							 DRV_TYPE_IO_1V8_ONLY,
+							 DRV_TYPE_IO_1V8_ONLY,
+							 DRV_TYPE_IO_DEFAULT,
+							 DRV_TYPE_IO_DEFAULT,
+							 0x0,
+							 0x8,
+							 -1,
+							 -1,
+							 PULL_TYPE_IO_1V8_ONLY,
+							 PULL_TYPE_IO_1V8_ONLY,
+							 PULL_TYPE_IO_DEFAULT,
+							 PULL_TYPE_IO_DEFAULT
+							),
 	PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(1, 32, "gpio1", IOMUX_SOURCE_PMU,
 					IOMUX_SOURCE_PMU,
 					IOMUX_SOURCE_PMU,
@@ -2578,11 +2648,15 @@ static struct rockchip_pin_bank rk3399_pin_banks[] = {
 					0x30,
 					0x38
 					),
-	PIN_BANK_DRV_FLAGS(2, 32, "gpio2", DRV_TYPE_IO_1V8_OR_3V0,
-			   DRV_TYPE_IO_1V8_OR_3V0,
-			   DRV_TYPE_IO_1V8_ONLY,
-			   DRV_TYPE_IO_1V8_ONLY
-			   ),
+	PIN_BANK_DRV_FLAGS_PULL_FLAGS(2, 32, "gpio2", DRV_TYPE_IO_1V8_OR_3V0,
+				      DRV_TYPE_IO_1V8_OR_3V0,
+				      DRV_TYPE_IO_1V8_ONLY,
+				      DRV_TYPE_IO_1V8_ONLY,
+				      PULL_TYPE_IO_DEFAULT,
+				      PULL_TYPE_IO_DEFAULT,
+				      PULL_TYPE_IO_1V8_ONLY,
+				      PULL_TYPE_IO_1V8_ONLY
+				      ),
 	PIN_BANK_DRV_FLAGS(3, 32, "gpio3", DRV_TYPE_IO_3V3_ONLY,
 			   DRV_TYPE_IO_3V3_ONLY,
 			   DRV_TYPE_IO_3V3_ONLY,
-- 
1.9.1



From w.egorov at phytec.de  Tue May 10 06:18:54 2016
From: w.egorov at phytec.de (Wadim Egorov)
Date: Tue, 10 May 2016 15:18:54 +0200
Subject: [PATCH v5 0/6] Add support for rk818
Message-ID: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>

Hello,

patches are based on top of

commit d5623161accb ("mfd: rk808: Use devm_mfd_add_devices() for mfd_device registration")

in linux-next.

Changes since v4:
- Added Acked-by from Mark Brown in patch 1
- Dropped a patch from this series which was applied by Mark Brown
  commit 129d7cf98f5c ("regulator: rk808: Add rk808_reg_ops_ranges for LDO3")

Wadim Egorov (6):
  regulator: rk808: Migrate to regulator core's simplified DT parsing
    code
  mfd: RK808: Add RK818 support
  regulator: rk808: Add regulator driver for RK818
  mfd: dt-bindings: Add RK818 device tree bindings document
  clk: Kconfig: Name RK818 in Kconfig for COMMON_CLK_RK808
  rtc: Kconfig: Name RK818 in Kconfig for RTC_DRV_RK808

 Documentation/devicetree/bindings/mfd/rk808.txt |  37 ++-
 drivers/clk/Kconfig                             |   4 +-
 drivers/mfd/Kconfig                             |   4 +-
 drivers/mfd/rk808.c                             | 231 ++++++++++++---
 drivers/regulator/Kconfig                       |   4 +-
 drivers/regulator/rk808-regulator.c             | 363 +++++++++++++-----------
 drivers/rtc/Kconfig                             |   4 +-
 include/linux/mfd/rk808.h                       | 162 ++++++++++-
 8 files changed, 590 insertions(+), 219 deletions(-)

-- 
1.9.1



From w.egorov at phytec.de  Tue May 10 06:18:58 2016
From: w.egorov at phytec.de (Wadim Egorov)
Date: Tue, 10 May 2016 15:18:58 +0200
Subject: [PATCH v5 4/6] mfd: dt-bindings: Add RK818 device tree bindings
 document
In-Reply-To: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
References: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
Message-ID: <1462886340-7893-5-git-send-email-w.egorov@phytec.de>

Add device tree bindings documentation for Rockchip's RK818 PMIC.

Signed-off-by: Wadim Egorov <w.egorov at phytec.de>
Acked-by: Rob Herring <robh at kernel.org>
---
 Documentation/devicetree/bindings/mfd/rk808.txt | 37 +++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/mfd/rk808.txt b/Documentation/devicetree/bindings/mfd/rk808.txt
index 4ca6aab..9636ae8 100644
--- a/Documentation/devicetree/bindings/mfd/rk808.txt
+++ b/Documentation/devicetree/bindings/mfd/rk808.txt
@@ -1,7 +1,11 @@
-RK808 Power Management Integrated Circuit
+RK8XX Power Management Integrated Circuit
+
+The rk8xx family current members:
+rk808
+rk818
 
 Required properties:
-- compatible: "rockchip,rk808"
+- compatible: "rockchip,rk808", "rockchip,rk818"
 - reg: I2C slave address
 - interrupt-parent: The parent interrupt controller.
 - interrupts: the interrupt outputs of the controller.
@@ -13,6 +17,8 @@ Optional properties:
   default output clock name
 - rockchip,system-power-controller: Telling whether or not this pmic is controlling
   the system power.
+
+Optional RK808 properties:
 - vcc1-supply:  The input supply for DCDC_REG1
 - vcc2-supply:  The input supply for DCDC_REG2
 - vcc3-supply:  The input supply for DCDC_REG3
@@ -29,7 +35,20 @@ Optional properties:
   the gpio controller. If DVS GPIOs aren't present, voltage changes will happen
   very quickly with no slow ramp time.
 
-Regulators: All the regulators of RK808 to be instantiated shall be
+Optional RK818 properties:
+- vcc1-supply:  The input supply for DCDC_REG1
+- vcc2-supply:  The input supply for DCDC_REG2
+- vcc3-supply:  The input supply for DCDC_REG3
+- vcc4-supply:  The input supply for DCDC_REG4
+- boost-supply: The input supply for DCDC_BOOST
+- vcc6-supply:  The input supply for LDO_REG1 and LDO_REG2
+- vcc7-supply:  The input supply for LDO_REG3, LDO_REG5 and LDO_REG7
+- vcc8-supply:  The input supply for LDO_REG4, LDO_REG6 and LDO_REG8
+- vcc9-supply:  The input supply for LDO_REG9 and SWITCH_REG
+- h_5v-supply:  The input supply for HDMI_SWITCH
+- usb-supply:   The input supply for OTG_SWITCH
+
+Regulators: All the regulators of RK8XX to be instantiated shall be
 listed in a child node named 'regulators'. Each regulator is represented
 by a child node of the 'regulators' node.
 
@@ -48,6 +67,18 @@ number as described in RK808 datasheet.
 	- SWITCH_REGn
 		- valid values for n are 1 to 2
 
+Following regulators of the RK818 PMIC block are supported. Note that
+the 'n' in regulator name, as in DCDC_REGn or LDOn, represents the DCDC or LDO
+number as described in RK818 datasheet.
+
+	- DCDC_REGn
+		- valid values for n are 1 to 4.
+	- LDO_REGn
+		- valid values for n are 1 to 9.
+	- SWITCH_REG
+	- HDMI_SWITCH
+	- OTG_SWITCH
+
 Standard regulator bindings are used inside regulator subnodes. Check
   Documentation/devicetree/bindings/regulator/regulator.txt
 for more details
-- 
1.9.1



From w.egorov at phytec.de  Tue May 10 06:18:55 2016
From: w.egorov at phytec.de (Wadim Egorov)
Date: Tue, 10 May 2016 15:18:55 +0200
Subject: [PATCH v5 1/6] regulator: rk808: Migrate to regulator core's
 simplified DT parsing code
In-Reply-To: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
References: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
Message-ID: <1462886340-7893-2-git-send-email-w.egorov@phytec.de>

A common simplified DT parsing code for regulators was introduced in
commit a0c7b164ad11 ("regulator: of: Provide simplified DT parsing
method")

While at it also added RK8XX_DESC and RK8XX_DESC_SWITCH macros for the
regulator_desc struct initialization. This just makes the driver more compact.

Signed-off-by: Wadim Egorov <w.egorov at phytec.de>
Acked-by: Mark Brown <broonie at kernel.org>
---
Changes since v4:
- Added acked-by
---
 drivers/regulator/rk808-regulator.c | 250 ++++++++++++------------------------
 1 file changed, 79 insertions(+), 171 deletions(-)

diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index 6601ab5..40d07ba 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -55,6 +55,42 @@
 /* max steps for increase voltage of Buck1/2, equal 100mv*/
 #define MAX_STEPS_ONE_TIME 8
 
+#define RK8XX_DESC(_id, _match, _supply, _min, _max, _step, _vreg,	\
+	_vmask, _ereg, _emask, _etime)					\
+	[_id] = {							\
+		.name		= (_match),				\
+		.supply_name	= (_supply),				\
+		.of_match	= of_match_ptr(_match),			\
+		.regulators_node = of_match_ptr("regulators"),		\
+		.type		= REGULATOR_VOLTAGE,			\
+		.id		= (_id),				\
+		.n_voltages	= (((_max) - (_min)) / (_step) + 1),	\
+		.owner		= THIS_MODULE,				\
+		.min_uV		= (_min) * 1000,			\
+		.uV_step	= (_step) * 1000,			\
+		.vsel_reg	= (_vreg),				\
+		.vsel_mask	= (_vmask),				\
+		.enable_reg	= (_ereg),				\
+		.enable_mask	= (_emask),				\
+		.enable_time	= (_etime),				\
+		.ops		= &rk808_reg_ops,			\
+	}
+
+#define RK8XX_DESC_SWITCH(_id, _match, _supply, _ereg, _emask)		\
+	[_id] = {							\
+		.name		= (_match),				\
+		.supply_name	= (_supply),				\
+		.of_match	= of_match_ptr(_match),			\
+		.regulators_node = of_match_ptr("regulators"),		\
+		.type		= REGULATOR_VOLTAGE,			\
+		.id		= (_id),				\
+		.enable_reg	= (_ereg),				\
+		.enable_mask	= (_emask),				\
+		.owner		= THIS_MODULE,				\
+		.ops		= &rk808_switch_ops			\
+	}
+
+
 struct rk808_regulator_data {
 	struct gpio_desc *dvs_gpio[2];
 };
@@ -328,6 +364,8 @@ static const struct regulator_desc rk808_reg[] = {
 	{
 		.name = "DCDC_REG1",
 		.supply_name = "vcc1",
+		.of_match = of_match_ptr("DCDC_REG1"),
+		.regulators_node = of_match_ptr("regulators"),
 		.id = RK808_ID_DCDC1,
 		.ops = &rk808_buck1_2_ops,
 		.type = REGULATOR_VOLTAGE,
@@ -342,6 +380,8 @@ static const struct regulator_desc rk808_reg[] = {
 	}, {
 		.name = "DCDC_REG2",
 		.supply_name = "vcc2",
+		.of_match = of_match_ptr("DCDC_REG2"),
+		.regulators_node = of_match_ptr("regulators"),
 		.id = RK808_ID_DCDC2,
 		.ops = &rk808_buck1_2_ops,
 		.type = REGULATOR_VOLTAGE,
@@ -356,6 +396,8 @@ static const struct regulator_desc rk808_reg[] = {
 	}, {
 		.name = "DCDC_REG3",
 		.supply_name = "vcc3",
+		.of_match = of_match_ptr("DCDC_REG3"),
+		.regulators_node = of_match_ptr("regulators"),
 		.id = RK808_ID_DCDC3,
 		.ops = &rk808_switch_ops,
 		.type = REGULATOR_VOLTAGE,
@@ -363,53 +405,21 @@ static const struct regulator_desc rk808_reg[] = {
 		.enable_reg = RK808_DCDC_EN_REG,
 		.enable_mask = BIT(2),
 		.owner = THIS_MODULE,
-	}, {
-		.name = "DCDC_REG4",
-		.supply_name = "vcc4",
-		.id = RK808_ID_DCDC4,
-		.ops = &rk808_reg_ops,
-		.type = REGULATOR_VOLTAGE,
-		.min_uV = 1800000,
-		.uV_step = 100000,
-		.n_voltages = 16,
-		.vsel_reg = RK808_BUCK4_ON_VSEL_REG,
-		.vsel_mask = RK808_BUCK4_VSEL_MASK,
-		.enable_reg = RK808_DCDC_EN_REG,
-		.enable_mask = BIT(3),
-		.owner = THIS_MODULE,
-	}, {
-		.name = "LDO_REG1",
-		.supply_name = "vcc6",
-		.id = RK808_ID_LDO1,
-		.ops = &rk808_reg_ops,
-		.type = REGULATOR_VOLTAGE,
-		.min_uV = 1800000,
-		.uV_step = 100000,
-		.n_voltages = 17,
-		.vsel_reg = RK808_LDO1_ON_VSEL_REG,
-		.vsel_mask = RK808_LDO_VSEL_MASK,
-		.enable_reg = RK808_LDO_EN_REG,
-		.enable_mask = BIT(0),
-		.enable_time = 400,
-		.owner = THIS_MODULE,
-	}, {
-		.name = "LDO_REG2",
-		.supply_name = "vcc6",
-		.id = RK808_ID_LDO2,
-		.ops = &rk808_reg_ops,
-		.type = REGULATOR_VOLTAGE,
-		.min_uV = 1800000,
-		.uV_step = 100000,
-		.n_voltages = 17,
-		.vsel_reg = RK808_LDO2_ON_VSEL_REG,
-		.vsel_mask = RK808_LDO_VSEL_MASK,
-		.enable_reg = RK808_LDO_EN_REG,
-		.enable_mask = BIT(1),
-		.enable_time = 400,
-		.owner = THIS_MODULE,
-	}, {
+	},
+	RK8XX_DESC(RK808_ID_DCDC4, "DCDC_REG4", "vcc4", 1800, 3300, 100,
+		RK808_BUCK4_ON_VSEL_REG, RK808_BUCK4_VSEL_MASK,
+		RK808_DCDC_EN_REG, BIT(3), 0),
+	RK8XX_DESC(RK808_ID_LDO1, "LDO_REG1", "vcc6", 1800, 3400, 100,
+		RK808_LDO1_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
+		BIT(0), 400),
+	RK8XX_DESC(RK808_ID_LDO2, "LDO_REG2", "vcc6", 1800, 3400, 100,
+		RK808_LDO2_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
+		BIT(1), 400),
+	{
 		.name = "LDO_REG3",
 		.supply_name = "vcc7",
+		.of_match = of_match_ptr("LDO_REG3"),
+		.regulators_node = of_match_ptr("regulators"),
 		.id = RK808_ID_LDO3,
 		.ops = &rk808_reg_ops_ranges,
 		.type = REGULATOR_VOLTAGE,
@@ -422,117 +432,26 @@ static const struct regulator_desc rk808_reg[] = {
 		.enable_mask = BIT(2),
 		.enable_time = 400,
 		.owner = THIS_MODULE,
-	}, {
-		.name = "LDO_REG4",
-		.supply_name = "vcc9",
-		.id = RK808_ID_LDO4,
-		.ops = &rk808_reg_ops,
-		.type = REGULATOR_VOLTAGE,
-		.min_uV = 1800000,
-		.uV_step = 100000,
-		.n_voltages = 17,
-		.vsel_reg = RK808_LDO4_ON_VSEL_REG,
-		.vsel_mask = RK808_LDO_VSEL_MASK,
-		.enable_reg = RK808_LDO_EN_REG,
-		.enable_mask = BIT(3),
-		.enable_time = 400,
-		.owner = THIS_MODULE,
-	}, {
-		.name = "LDO_REG5",
-		.supply_name = "vcc9",
-		.id = RK808_ID_LDO5,
-		.ops = &rk808_reg_ops,
-		.type = REGULATOR_VOLTAGE,
-		.min_uV = 1800000,
-		.uV_step = 100000,
-		.n_voltages = 17,
-		.vsel_reg = RK808_LDO5_ON_VSEL_REG,
-		.vsel_mask = RK808_LDO_VSEL_MASK,
-		.enable_reg = RK808_LDO_EN_REG,
-		.enable_mask = BIT(4),
-		.enable_time = 400,
-		.owner = THIS_MODULE,
-	}, {
-		.name = "LDO_REG6",
-		.supply_name = "vcc10",
-		.id = RK808_ID_LDO6,
-		.ops = &rk808_reg_ops,
-		.type = REGULATOR_VOLTAGE,
-		.min_uV = 800000,
-		.uV_step = 100000,
-		.n_voltages = 18,
-		.vsel_reg = RK808_LDO6_ON_VSEL_REG,
-		.vsel_mask = RK808_LDO_VSEL_MASK,
-		.enable_reg = RK808_LDO_EN_REG,
-		.enable_mask = BIT(5),
-		.enable_time = 400,
-		.owner = THIS_MODULE,
-	}, {
-		.name = "LDO_REG7",
-		.supply_name = "vcc7",
-		.id = RK808_ID_LDO7,
-		.ops = &rk808_reg_ops,
-		.type = REGULATOR_VOLTAGE,
-		.min_uV = 800000,
-		.uV_step = 100000,
-		.n_voltages = 18,
-		.vsel_reg = RK808_LDO7_ON_VSEL_REG,
-		.vsel_mask = RK808_LDO_VSEL_MASK,
-		.enable_reg = RK808_LDO_EN_REG,
-		.enable_mask = BIT(6),
-		.enable_time = 400,
-		.owner = THIS_MODULE,
-	}, {
-		.name = "LDO_REG8",
-		.supply_name = "vcc11",
-		.id = RK808_ID_LDO8,
-		.ops = &rk808_reg_ops,
-		.type = REGULATOR_VOLTAGE,
-		.min_uV = 1800000,
-		.uV_step = 100000,
-		.n_voltages = 17,
-		.vsel_reg = RK808_LDO8_ON_VSEL_REG,
-		.vsel_mask = RK808_LDO_VSEL_MASK,
-		.enable_reg = RK808_LDO_EN_REG,
-		.enable_mask = BIT(7),
-		.enable_time = 400,
-		.owner = THIS_MODULE,
-	}, {
-		.name = "SWITCH_REG1",
-		.supply_name = "vcc8",
-		.id = RK808_ID_SWITCH1,
-		.ops = &rk808_switch_ops,
-		.type = REGULATOR_VOLTAGE,
-		.enable_reg = RK808_DCDC_EN_REG,
-		.enable_mask = BIT(5),
-		.owner = THIS_MODULE,
-	}, {
-		.name = "SWITCH_REG2",
-		.supply_name = "vcc12",
-		.id = RK808_ID_SWITCH2,
-		.ops = &rk808_switch_ops,
-		.type = REGULATOR_VOLTAGE,
-		.enable_reg = RK808_DCDC_EN_REG,
-		.enable_mask = BIT(6),
-		.owner = THIS_MODULE,
 	},
-};
-
-static struct of_regulator_match rk808_reg_matches[] = {
-	[RK808_ID_DCDC1]	= { .name = "DCDC_REG1" },
-	[RK808_ID_DCDC2]	= { .name = "DCDC_REG2" },
-	[RK808_ID_DCDC3]	= { .name = "DCDC_REG3" },
-	[RK808_ID_DCDC4]	= { .name = "DCDC_REG4" },
-	[RK808_ID_LDO1]		= { .name = "LDO_REG1" },
-	[RK808_ID_LDO2]		= { .name = "LDO_REG2" },
-	[RK808_ID_LDO3]		= { .name = "LDO_REG3" },
-	[RK808_ID_LDO4]		= { .name = "LDO_REG4" },
-	[RK808_ID_LDO5]		= { .name = "LDO_REG5" },
-	[RK808_ID_LDO6]		= { .name = "LDO_REG6" },
-	[RK808_ID_LDO7]		= { .name = "LDO_REG7" },
-	[RK808_ID_LDO8]		= { .name = "LDO_REG8" },
-	[RK808_ID_SWITCH1]	= { .name = "SWITCH_REG1" },
-	[RK808_ID_SWITCH2]	= { .name = "SWITCH_REG2" },
+	RK8XX_DESC(RK808_ID_LDO4, "LDO_REG4", "vcc9", 1800, 3400, 100,
+		RK808_LDO4_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
+		BIT(3), 400),
+	RK8XX_DESC(RK808_ID_LDO5, "LDO_REG5", "vcc9", 1800, 3400, 100,
+		RK808_LDO5_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
+		BIT(4), 400),
+	RK8XX_DESC(RK808_ID_LDO6, "LDO_REG6", "vcc10", 800, 2500, 100,
+		RK808_LDO6_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
+		BIT(5), 400),
+	RK8XX_DESC(RK808_ID_LDO7, "LDO_REG7", "vcc7", 800, 2500, 100,
+		RK808_LDO7_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
+		BIT(6), 400),
+	RK8XX_DESC(RK808_ID_LDO8, "LDO_REG8", "vcc11", 1800, 3400, 100,
+		RK808_LDO8_ON_VSEL_REG, RK808_LDO_VSEL_MASK, RK808_LDO_EN_REG,
+		BIT(7), 400),
+	RK8XX_DESC_SWITCH(RK808_ID_SWITCH1, "SWITCH_REG1", "vcc8",
+		RK808_DCDC_EN_REG, BIT(5)),
+	RK8XX_DESC_SWITCH(RK808_ID_SWITCH2, "SWITCH_REG2", "vcc12",
+		RK808_DCDC_EN_REG, BIT(6)),
 };
 
 static int rk808_regulator_dt_parse_pdata(struct device *dev,
@@ -541,17 +460,12 @@ static int rk808_regulator_dt_parse_pdata(struct device *dev,
 				   struct rk808_regulator_data *pdata)
 {
 	struct device_node *np;
-	int tmp, ret, i;
+	int tmp, ret = 0, i;
 
 	np = of_get_child_by_name(client_dev->of_node, "regulators");
 	if (!np)
 		return -ENXIO;
 
-	ret = of_regulator_match(dev, np, rk808_reg_matches,
-				 RK808_NUM_REGULATORS);
-	if (ret < 0)
-		goto dt_parse_end;
-
 	for (i = 0; i < ARRAY_SIZE(pdata->dvs_gpio); i++) {
 		pdata->dvs_gpio[i] =
 			devm_gpiod_get_index_optional(client_dev, "dvs", i,
@@ -598,18 +512,12 @@ static int rk808_regulator_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, pdata);
 
+	config.dev = &client->dev;
+	config.driver_data = pdata;
+	config.regmap = rk808->regmap;
+
 	/* Instantiate the regulators */
 	for (i = 0; i < RK808_NUM_REGULATORS; i++) {
-		if (!rk808_reg_matches[i].init_data ||
-		    !rk808_reg_matches[i].of_node)
-			continue;
-
-		config.dev = &client->dev;
-		config.driver_data = pdata;
-		config.regmap = rk808->regmap;
-		config.of_node = rk808_reg_matches[i].of_node;
-		config.init_data = rk808_reg_matches[i].init_data;
-
 		rk808_rdev = devm_regulator_register(&pdev->dev,
 						     &rk808_reg[i], &config);
 		if (IS_ERR(rk808_rdev)) {
-- 
1.9.1



From w.egorov at phytec.de  Tue May 10 06:18:57 2016
From: w.egorov at phytec.de (Wadim Egorov)
Date: Tue, 10 May 2016 15:18:57 +0200
Subject: [PATCH v5 3/6] regulator: rk808: Add regulator driver for RK818
In-Reply-To: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
References: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
Message-ID: <1462886340-7893-4-git-send-email-w.egorov@phytec.de>

Add support for the rk818 regulator. The regulator module consists
of 4 DCDCs, 9 LDOs, 1 switch and 1 BOOST converter which is used to
power OTG and HDMI5V.

The output voltages are configurable and are meant to supply power
to the main processor and other components.

Signed-off-by: Wadim Egorov <w.egorov at phytec.de>
---
 drivers/regulator/Kconfig           |   4 +-
 drivers/regulator/rk808-regulator.c | 143 ++++++++++++++++++++++++++++++++++--
 2 files changed, 138 insertions(+), 9 deletions(-)

diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 8e665e2..234131a 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -617,11 +617,11 @@ config REGULATOR_RC5T583
 	  outputs which can be controlled by i2c communication.
 
 config REGULATOR_RK808
-	tristate "Rockchip RK808 Power regulators"
+	tristate "Rockchip RK808/RK818 Power regulators"
 	depends on MFD_RK808
 	help
 	  Select this option to enable the power regulator of ROCKCHIP
-	  PMIC RK808.
+	  PMIC RK808 and RK818.
 	  This driver supports the control of different power rails of device
 	  through regulator interface. The device supports multiple DCDC/LDO
 	  outputs which can be controlled by i2c communication.
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index 40d07ba..5f412a5 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -1,11 +1,15 @@
 /*
- * Regulator driver for Rockchip RK808
+ * Regulator driver for Rockchip RK808/RK818
  *
  * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
  *
  * Author: Chris Zhong <zyw at rock-chips.com>
  * Author: Zhang Qing <zhangqing at rock-chips.com>
  *
+ * Copyright (C) 2016 PHYTEC Messtechnik GmbH
+ *
+ * Author: Wadim Egorov <w.egorov at phytec.de>
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  * version 2, as published by the Free Software Foundation.
@@ -32,6 +36,12 @@
 #define RK808_BUCK4_VSEL_MASK	0xf
 #define RK808_LDO_VSEL_MASK	0x1f
 
+#define RK818_BUCK_VSEL_MASK		0x3f
+#define RK818_BUCK4_VSEL_MASK		0x1f
+#define RK818_LDO_VSEL_MASK		0x1f
+#define RK818_LDO3_ON_VSEL_MASK		0xf
+#define RK818_BOOST_ON_VSEL_MASK	0xe0
+
 /* Ramp rate definitions for buck1 / buck2 only */
 #define RK808_RAMP_RATE_OFFSET		3
 #define RK808_RAMP_RATE_MASK		(3 << RK808_RAMP_RATE_OFFSET)
@@ -454,6 +464,108 @@ static const struct regulator_desc rk808_reg[] = {
 		RK808_DCDC_EN_REG, BIT(6)),
 };
 
+static const struct regulator_desc rk818_reg[] = {
+	{
+		.name = "DCDC_REG1",
+		.supply_name = "vcc1",
+		.of_match = of_match_ptr("DCDC_REG1"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = RK818_ID_DCDC1,
+		.ops = &rk808_reg_ops,
+		.type = REGULATOR_VOLTAGE,
+		.min_uV = 712500,
+		.uV_step = 12500,
+		.n_voltages = 64,
+		.vsel_reg = RK818_BUCK1_ON_VSEL_REG,
+		.vsel_mask = RK818_BUCK_VSEL_MASK,
+		.enable_reg = RK818_DCDC_EN_REG,
+		.enable_mask = BIT(0),
+		.owner = THIS_MODULE,
+	}, {
+		.name = "DCDC_REG2",
+		.supply_name = "vcc2",
+		.of_match = of_match_ptr("DCDC_REG2"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = RK818_ID_DCDC2,
+		.ops = &rk808_reg_ops,
+		.type = REGULATOR_VOLTAGE,
+		.min_uV = 712500,
+		.uV_step = 12500,
+		.n_voltages = 64,
+		.vsel_reg = RK818_BUCK2_ON_VSEL_REG,
+		.vsel_mask = RK818_BUCK_VSEL_MASK,
+		.enable_reg = RK818_DCDC_EN_REG,
+		.enable_mask = BIT(1),
+		.owner = THIS_MODULE,
+	}, {
+		.name = "DCDC_REG3",
+		.supply_name = "vcc3",
+		.of_match = of_match_ptr("DCDC_REG3"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = RK818_ID_DCDC3,
+		.ops = &rk808_switch_ops,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = 1,
+		.enable_reg = RK818_DCDC_EN_REG,
+		.enable_mask = BIT(2),
+		.owner = THIS_MODULE,
+	},
+	RK8XX_DESC(RK818_ID_DCDC4, "DCDC_REG4", "vcc4", 1800, 3600, 100,
+		RK818_BUCK4_ON_VSEL_REG, RK818_BUCK4_VSEL_MASK,
+		RK818_DCDC_EN_REG, BIT(3), 0),
+	RK8XX_DESC(RK818_ID_BOOST, "DCDC_BOOST", "boost", 4700, 5400, 100,
+		RK818_BOOST_LDO9_ON_VSEL_REG, RK818_BOOST_ON_VSEL_MASK,
+		RK818_DCDC_EN_REG, BIT(4), 0),
+	RK8XX_DESC(RK818_ID_LDO1, "LDO_REG1", "vcc6", 1800, 3400, 100,
+		RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+		BIT(0), 400),
+	RK8XX_DESC(RK818_ID_LDO2, "LDO_REG2", "vcc6", 1800, 3400, 100,
+		RK818_LDO1_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+		BIT(1), 400),
+	{
+		.name = "LDO_REG3",
+		.supply_name = "vcc7",
+		.of_match = of_match_ptr("LDO_REG3"),
+		.regulators_node = of_match_ptr("regulators"),
+		.id = RK818_ID_LDO3,
+		.ops = &rk808_reg_ops_ranges,
+		.type = REGULATOR_VOLTAGE,
+		.n_voltages = 16,
+		.linear_ranges = rk808_ldo3_voltage_ranges,
+		.n_linear_ranges = ARRAY_SIZE(rk808_ldo3_voltage_ranges),
+		.vsel_reg = RK818_LDO3_ON_VSEL_REG,
+		.vsel_mask = RK818_LDO3_ON_VSEL_MASK,
+		.enable_reg = RK818_LDO_EN_REG,
+		.enable_mask = BIT(2),
+		.enable_time = 400,
+		.owner = THIS_MODULE,
+	},
+	RK8XX_DESC(RK818_ID_LDO4, "LDO_REG4", "vcc8", 1800, 3400, 100,
+		RK818_LDO4_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+		BIT(3), 400),
+	RK8XX_DESC(RK818_ID_LDO5, "LDO_REG5", "vcc7", 1800, 3400, 100,
+		RK818_LDO5_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+		BIT(4), 400),
+	RK8XX_DESC(RK818_ID_LDO6, "LDO_REG6", "vcc8", 800, 2500, 100,
+		RK818_LDO6_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+		BIT(5), 400),
+	RK8XX_DESC(RK818_ID_LDO7, "LDO_REG7", "vcc7", 800, 2500, 100,
+		RK818_LDO7_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+		BIT(6), 400),
+	RK8XX_DESC(RK818_ID_LDO8, "LDO_REG8", "vcc8", 1800, 3400, 100,
+		RK818_LDO8_ON_VSEL_REG, RK818_LDO_VSEL_MASK, RK818_LDO_EN_REG,
+		BIT(7), 400),
+	RK8XX_DESC(RK818_ID_LDO9, "LDO_REG9", "vcc9", 1800, 3400, 100,
+		RK818_BOOST_LDO9_ON_VSEL_REG, RK818_LDO_VSEL_MASK,
+		RK818_DCDC_EN_REG, BIT(5), 400),
+	RK8XX_DESC_SWITCH(RK818_ID_SWITCH, "SWITCH_REG", "vcc9",
+		RK818_DCDC_EN_REG, BIT(6)),
+	RK8XX_DESC_SWITCH(RK818_ID_HDMI_SWITCH, "HDMI_SWITCH", "h_5v",
+		RK818_H5V_EN_REG, BIT(0)),
+	RK8XX_DESC_SWITCH(RK818_ID_OTG_SWITCH, "OTG_SWITCH", "usb",
+		RK818_DCDC_EN_REG, BIT(7)),
+};
+
 static int rk808_regulator_dt_parse_pdata(struct device *dev,
 				   struct device *client_dev,
 				   struct regmap *map,
@@ -499,7 +611,8 @@ static int rk808_regulator_probe(struct platform_device *pdev)
 	struct regulator_config config = {};
 	struct regulator_dev *rk808_rdev;
 	struct rk808_regulator_data *pdata;
-	int ret, i;
+	const struct regulator_desc *regulators;
+	int ret, i, nregulators;
 
 	pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
@@ -512,14 +625,29 @@ static int rk808_regulator_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, pdata);
 
+	switch (rk808->variant) {
+	case RK808_ID:
+		regulators = rk808_reg;
+		nregulators = RK808_NUM_REGULATORS;
+		break;
+	case RK818_ID:
+		regulators = rk818_reg;
+		nregulators = RK818_NUM_REGULATORS;
+		break;
+	default:
+		dev_err(&client->dev, "unsupported RK8XX ID %lu\n",
+			rk808->variant);
+		return -EINVAL;
+	}
+
 	config.dev = &client->dev;
 	config.driver_data = pdata;
 	config.regmap = rk808->regmap;
 
 	/* Instantiate the regulators */
-	for (i = 0; i < RK808_NUM_REGULATORS; i++) {
+	for (i = 0; i < nregulators; i++) {
 		rk808_rdev = devm_regulator_register(&pdev->dev,
-						     &rk808_reg[i], &config);
+						     &regulators[i], &config);
 		if (IS_ERR(rk808_rdev)) {
 			dev_err(&client->dev,
 				"failed to register %d regulator\n", i);
@@ -540,8 +668,9 @@ static struct platform_driver rk808_regulator_driver = {
 
 module_platform_driver(rk808_regulator_driver);
 
-MODULE_DESCRIPTION("regulator driver for the rk808 series PMICs");
-MODULE_AUTHOR("Chris Zhong<zyw at rock-chips.com>");
-MODULE_AUTHOR("Zhang Qing<zhangqing at rock-chips.com>");
+MODULE_DESCRIPTION("regulator driver for the RK808/RK818 series PMICs");
+MODULE_AUTHOR("Chris Zhong <zyw at rock-chips.com>");
+MODULE_AUTHOR("Zhang Qing <zhangqing at rock-chips.com>");
+MODULE_AUTHOR("Wadim Egorov <w.egorov at phytec.de>");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:rk808-regulator");
-- 
1.9.1



From w.egorov at phytec.de  Tue May 10 06:18:56 2016
From: w.egorov at phytec.de (Wadim Egorov)
Date: Tue, 10 May 2016 15:18:56 +0200
Subject: [PATCH v5 2/6] mfd: RK808: Add RK818 support
In-Reply-To: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
References: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
Message-ID: <1462886340-7893-3-git-send-email-w.egorov@phytec.de>

The RK818 chip is a power management IC for multimedia and handheld
devices. It contains the following components:

- Regulators
- RTC
- Clkout
- battery support

Both chips RK808 and RK818 are using a similar register map.
So we can reuse the RTC and Clkout functionality.

Signed-off-by: Wadim Egorov <w.egorov at phytec.de>
---
Changes since v4:
- rebased on top of
  commit d5623161accb ("mfd: rk808: Use devm_mfd_add_devices() for mfd_device registration")
---
 drivers/mfd/Kconfig       |   4 +-
 drivers/mfd/rk808.c       | 231 ++++++++++++++++++++++++++++++++++++++--------
 include/linux/mfd/rk808.h | 162 ++++++++++++++++++++++++++++++--
 3 files changed, 350 insertions(+), 47 deletions(-)

diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index a49565c..c50ce1e5 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -829,13 +829,13 @@ config MFD_RC5T583
 	  different functionality of the device.
 
 config MFD_RK808
-	tristate "Rockchip RK808 Power Management chip"
+	tristate "Rockchip RK808/RK818 Power Management chip"
 	depends on I2C && OF
 	select MFD_CORE
 	select REGMAP_I2C
 	select REGMAP_IRQ
 	help
-	  If you say yes here you get support for the RK808
+	  If you say yes here you get support for the RK808 and RK818
 	  Power Management chips.
 	  This driver provides common support for accessing the device
 	  through I2C interface. The device supports multiple sub-devices
diff --git a/drivers/mfd/rk808.c b/drivers/mfd/rk808.c
index 49d7f62..3cf9724 100644
--- a/drivers/mfd/rk808.c
+++ b/drivers/mfd/rk808.c
@@ -1,11 +1,15 @@
 /*
- * MFD core driver for Rockchip RK808
+ * MFD core driver for Rockchip RK808/RK818
  *
  * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
  *
  * Author: Chris Zhong <zyw at rock-chips.com>
  * Author: Zhang Qing <zhangqing at rock-chips.com>
  *
+ * Copyright (C) 2016 PHYTEC Messtechnik GmbH
+ *
+ * Author: Wadim Egorov <w.egorov at phytec.de>
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  * version 2, as published by the Free Software Foundation.
@@ -22,12 +26,7 @@
 #include <linux/mfd/core.h>
 #include <linux/module.h>
 #include <linux/regmap.h>
-
-struct rk808_reg_data {
-	int addr;
-	int mask;
-	int value;
-};
+#include <linux/of_device.h>
 
 static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
 {
@@ -57,6 +56,14 @@ static bool rk808_is_volatile_reg(struct device *dev, unsigned int reg)
 	return false;
 }
 
+static const struct regmap_config rk818_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.max_register = RK818_USB_CTRL_REG,
+	.cache_type = REGCACHE_RBTREE,
+	.volatile_reg = rk808_is_volatile_reg,
+};
+
 static const struct regmap_config rk808_regmap_config = {
 	.reg_bits = 8,
 	.val_bits = 8,
@@ -83,7 +90,17 @@ static const struct mfd_cell rk808s[] = {
 	},
 };
 
-static const struct rk808_reg_data pre_init_reg[] = {
+static const struct mfd_cell rk818s[] = {
+	{ .name = "rk808-clkout", },
+	{ .name = "rk808-regulator", },
+	{
+		.name = "rk808-rtc",
+		.num_resources = ARRAY_SIZE(rtc_resources),
+		.resources = &rtc_resources[0],
+	},
+};
+
+static const struct rk8xx_reg_data rk808_pre_init_reg[] = {
 	{ RK808_BUCK3_CONFIG_REG, BUCK_ILMIN_MASK,  BUCK_ILMIN_150MA },
 	{ RK808_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK,  BUCK_ILMIN_200MA },
 	{ RK808_BOOST_CONFIG_REG, BOOST_ILMIN_MASK, BOOST_ILMIN_100MA },
@@ -94,6 +111,22 @@ static const struct rk808_reg_data pre_init_reg[] = {
 						    VB_LO_SEL_3500MV },
 };
 
+static const struct rk8xx_reg_data rk818_pre_init_reg[] = {
+	{ RK818_USB_CTRL_REG,	RK818_USB_ILIM_SEL_MASK,
+						RK818_USB_ILMIN_2000MA },
+	/* close charger when usb lower then 3.4V */
+	{ RK818_USB_CTRL_REG,	RK818_USB_CHG_SD_VSEL_MASK, (0x7 << 4) },
+	/* no action when vref */
+	{ RK818_H5V_EN_REG,	BIT(1),		RK818_REF_RDY_CTRL },
+	/* enable HDMI 5V */
+	{ RK818_H5V_EN_REG,	BIT(0),		RK818_H5V_EN },
+	/* improve efficiency */
+	{ RK818_BUCK2_CONFIG_REG, BUCK2_RATE_MASK,	BUCK_ILMIN_250MA },
+	{ RK818_BUCK4_CONFIG_REG, BUCK_ILMIN_MASK,	BUCK_ILMIN_250MA },
+	{ RK818_BOOST_CONFIG_REG, BOOST_ILMIN_MASK,	BOOST_ILMIN_100MA },
+	{ RK808_VB_MON_REG,	MASK_ALL,	VB_LO_ACT | VB_LO_SEL_3500MV },
+};
+
 static const struct regmap_irq rk808_irqs[] = {
 	/* INT_STS */
 	[RK808_IRQ_VOUT_LO] = {
@@ -136,6 +169,76 @@ static const struct regmap_irq rk808_irqs[] = {
 	},
 };
 
+static const struct regmap_irq rk818_irqs[] = {
+	/* INT_STS */
+	[RK818_IRQ_VOUT_LO] = {
+		.mask = RK818_IRQ_VOUT_LO_MSK,
+		.reg_offset = 0,
+	},
+	[RK818_IRQ_VB_LO] = {
+		.mask = RK818_IRQ_VB_LO_MSK,
+		.reg_offset = 0,
+	},
+	[RK818_IRQ_PWRON] = {
+		.mask = RK818_IRQ_PWRON_MSK,
+		.reg_offset = 0,
+	},
+	[RK818_IRQ_PWRON_LP] = {
+		.mask = RK818_IRQ_PWRON_LP_MSK,
+		.reg_offset = 0,
+	},
+	[RK818_IRQ_HOTDIE] = {
+		.mask = RK818_IRQ_HOTDIE_MSK,
+		.reg_offset = 0,
+	},
+	[RK818_IRQ_RTC_ALARM] = {
+		.mask = RK818_IRQ_RTC_ALARM_MSK,
+		.reg_offset = 0,
+	},
+	[RK818_IRQ_RTC_PERIOD] = {
+		.mask = RK818_IRQ_RTC_PERIOD_MSK,
+		.reg_offset = 0,
+	},
+	[RK818_IRQ_USB_OV] = {
+		.mask = RK818_IRQ_USB_OV_MSK,
+		.reg_offset = 0,
+	},
+
+	/* INT_STS2 */
+	[RK818_IRQ_PLUG_IN] = {
+		.mask = RK818_IRQ_PLUG_IN_MSK,
+		.reg_offset = 1,
+	},
+	[RK818_IRQ_PLUG_OUT] = {
+		.mask = RK818_IRQ_PLUG_OUT_MSK,
+		.reg_offset = 1,
+	},
+	[RK818_IRQ_CHG_OK] = {
+		.mask = RK818_IRQ_CHG_OK_MSK,
+		.reg_offset = 1,
+	},
+	[RK818_IRQ_CHG_TE] = {
+		.mask = RK818_IRQ_CHG_TE_MSK,
+		.reg_offset = 1,
+	},
+	[RK818_IRQ_CHG_TS1] = {
+		.mask = RK818_IRQ_CHG_TS1_MSK,
+		.reg_offset = 1,
+	},
+	[RK818_IRQ_TS2] = {
+		.mask = RK818_IRQ_TS2_MSK,
+		.reg_offset = 1,
+	},
+	[RK818_IRQ_CHG_CVTLIM] = {
+		.mask = RK818_IRQ_CHG_CVTLIM_MSK,
+		.reg_offset = 1,
+	},
+	[RK818_IRQ_DISCHG_ILIM] = {
+		.mask = RK818_IRQ_DISCHG_ILIM_MSK,
+		.reg_offset = 1,
+	},
+};
+
 static struct regmap_irq_chip rk808_irq_chip = {
 	.name = "rk808",
 	.irqs = rk808_irqs,
@@ -148,6 +251,18 @@ static struct regmap_irq_chip rk808_irq_chip = {
 	.init_ack_masked = true,
 };
 
+static struct regmap_irq_chip rk818_irq_chip = {
+	.name = "rk818",
+	.irqs = rk818_irqs,
+	.num_irqs = ARRAY_SIZE(rk818_irqs),
+	.num_regs = 2,
+	.irq_reg_stride = 2,
+	.status_base = RK818_INT_STS_REG1,
+	.mask_base = RK818_INT_STS_MSK_REG1,
+	.ack_base = RK818_INT_STS_REG1,
+	.init_ack_masked = true,
+};
+
 static struct i2c_client *rk808_i2c_client;
 static void rk808_device_shutdown(void)
 {
@@ -167,6 +282,48 @@ static void rk808_device_shutdown(void)
 		dev_err(&rk808_i2c_client->dev, "power off error!\n");
 }
 
+static const struct of_device_id rk808_of_match[] = {
+	{ .compatible = "rockchip,rk808", .data = (void *) RK808_ID },
+	{ .compatible = "rockchip,rk818", .data = (void *) RK818_ID },
+	{ },
+};
+MODULE_DEVICE_TABLE(of, rk808_of_match);
+
+static int rk8xx_match_device(struct rk808 *rk808, struct device *dev)
+{
+	const struct of_device_id *of_id;
+
+	of_id = of_match_device(rk808_of_match, dev);
+	if (!of_id) {
+		dev_err(dev, "Unable to match OF ID\n");
+		return -ENODEV;
+	}
+	rk808->variant = (long) of_id->data;
+
+	switch (rk808->variant) {
+	case RK808_ID:
+		rk808->nr_cells = ARRAY_SIZE(rk808s);
+		rk808->cells = rk808s;
+		rk808->regmap_cfg = &rk808_regmap_config;
+		rk808->regmap_irq_chip = &rk808_irq_chip;
+		rk808->pre_init_reg = rk808_pre_init_reg;
+		rk808->nr_pre_init_regs = ARRAY_SIZE(rk808_pre_init_reg);
+		break;
+	case RK818_ID:
+		rk808->nr_cells = ARRAY_SIZE(rk818s);
+		rk808->cells = rk818s;
+		rk808->regmap_cfg = &rk818_regmap_config;
+		rk808->regmap_irq_chip = &rk818_irq_chip;
+		rk808->pre_init_reg = rk818_pre_init_reg;
+		rk808->nr_pre_init_regs = ARRAY_SIZE(rk818_pre_init_reg);
+		break;
+	default:
+		dev_err(dev, "unsupported RK8XX ID %lu\n", rk808->variant);
+		return -EINVAL;
+	}
+
+	return 0;
+}
 static int rk808_probe(struct i2c_client *client,
 		       const struct i2c_device_id *id)
 {
@@ -176,46 +333,52 @@ static int rk808_probe(struct i2c_client *client,
 	int ret;
 	int i;
 
-	if (!client->irq) {
-		dev_err(&client->dev, "No interrupt support, no core IRQ\n");
-		return -EINVAL;
-	}
-
 	rk808 = devm_kzalloc(&client->dev, sizeof(*rk808), GFP_KERNEL);
 	if (!rk808)
 		return -ENOMEM;
 
-	rk808->regmap = devm_regmap_init_i2c(client, &rk808_regmap_config);
+	ret = rk8xx_match_device(rk808, &client->dev);
+	if (ret)
+		return ret;
+
+	rk808->i2c = client;
+	i2c_set_clientdata(client, rk808);
+
+	rk808->regmap = devm_regmap_init_i2c(client, rk808->regmap_cfg);
 	if (IS_ERR(rk808->regmap)) {
 		dev_err(&client->dev, "regmap initialization failed\n");
 		return PTR_ERR(rk808->regmap);
 	}
 
-	for (i = 0; i < ARRAY_SIZE(pre_init_reg); i++) {
-		ret = regmap_update_bits(rk808->regmap, pre_init_reg[i].addr,
-					 pre_init_reg[i].mask,
-					 pre_init_reg[i].value);
-		if (ret) {
-			dev_err(&client->dev,
-				"0x%x write err\n", pre_init_reg[i].addr);
-			return ret;
-		}
+	if (!client->irq) {
+		dev_err(&client->dev, "No interrupt support, no core IRQ\n");
+		return -EINVAL;
 	}
 
 	ret = regmap_add_irq_chip(rk808->regmap, client->irq,
 				  IRQF_ONESHOT, -1,
-				  &rk808_irq_chip, &rk808->irq_data);
+				  rk808->regmap_irq_chip, &rk808->irq_data);
 	if (ret) {
 		dev_err(&client->dev, "Failed to add irq_chip %d\n", ret);
 		return ret;
 	}
 
-	rk808->i2c = client;
-	i2c_set_clientdata(client, rk808);
+	for (i = 0; i < rk808->nr_pre_init_regs; i++) {
+		ret = regmap_update_bits(rk808->regmap,
+					rk808->pre_init_reg[i].addr,
+					rk808->pre_init_reg[i].mask,
+					rk808->pre_init_reg[i].value);
+		if (ret) {
+			dev_err(&client->dev,
+				"0x%x write err\n",
+				rk808->pre_init_reg[i].addr);
+			return ret;
+		}
+	}
 
-	ret = devm_mfd_add_devices(&client->dev, -1,
-				   rk808s, ARRAY_SIZE(rk808s), NULL, 0,
-				   regmap_irq_get_domain(rk808->irq_data));
+	ret = devm_mfd_add_devices(&client->dev, PLATFORM_DEVID_NONE,
+			      rk808->cells, rk808->nr_cells, NULL, 0,
+			      regmap_irq_get_domain(rk808->irq_data));
 	if (ret) {
 		dev_err(&client->dev, "failed to add MFD devices %d\n", ret);
 		goto err_irq;
@@ -245,14 +408,9 @@ static int rk808_remove(struct i2c_client *client)
 	return 0;
 }
 
-static const struct of_device_id rk808_of_match[] = {
-	{ .compatible = "rockchip,rk808" },
-	{ },
-};
-MODULE_DEVICE_TABLE(of, rk808_of_match);
-
 static const struct i2c_device_id rk808_ids[] = {
 	{ "rk808" },
+	{ "rk818" },
 	{ },
 };
 MODULE_DEVICE_TABLE(i2c, rk808_ids);
@@ -272,4 +430,5 @@ module_i2c_driver(rk808_i2c_driver);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Chris Zhong <zyw at rock-chips.com>");
 MODULE_AUTHOR("Zhang Qing <zhangqing at rock-chips.com>");
-MODULE_DESCRIPTION("RK808 PMIC driver");
+MODULE_AUTHOR("Wadim Egorov <w.egorov at phytec.de>");
+MODULE_DESCRIPTION("RK808/RK818 PMIC driver");
diff --git a/include/linux/mfd/rk808.h b/include/linux/mfd/rk808.h
index 441b6ee..5ce810c 100644
--- a/include/linux/mfd/rk808.h
+++ b/include/linux/mfd/rk808.h
@@ -1,11 +1,15 @@
 /*
- * rk808.h for Rockchip RK808
+ * Register definitions for Rockchip's RK808/RK818 PMIC
  *
  * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
  *
  * Author: Chris Zhong <zyw at rock-chips.com>
  * Author: Zhang Qing <zhangqing at rock-chips.com>
  *
+ * Copyright (C) 2016 PHYTEC Messtechnik GmbH
+ *
+ * Author: Wadim Egorov <w.egorov at phytec.de>
+ *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms and conditions of the GNU General Public License,
  * version 2, as published by the Free Software Foundation.
@@ -16,8 +20,8 @@
  * more details.
  */
 
-#ifndef __LINUX_REGULATOR_rk808_H
-#define __LINUX_REGULATOR_rk808_H
+#ifndef __LINUX_REGULATOR_RK808_H
+#define __LINUX_REGULATOR_RK808_H
 
 #include <linux/regulator/machine.h>
 #include <linux/regmap.h>
@@ -28,7 +32,7 @@
 
 #define RK808_DCDC1	0 /* (0+RK808_START) */
 #define RK808_LDO1	4 /* (4+RK808_START) */
-#define RK808_NUM_REGULATORS   14
+#define RK808_NUM_REGULATORS	14
 
 enum rk808_reg {
 	RK808_ID_DCDC1,
@@ -115,7 +119,92 @@ enum rk808_reg {
 #define RK808_INT_STS_MSK_REG2	0x4f
 #define RK808_IO_POL_REG	0x50
 
-/* IRQ Definitions */
+/* RK818 */
+#define RK818_DCDC1			0
+#define RK818_LDO1			4
+#define RK818_NUM_REGULATORS		17
+
+enum rk818_reg {
+	RK818_ID_DCDC1,
+	RK818_ID_DCDC2,
+	RK818_ID_DCDC3,
+	RK818_ID_DCDC4,
+	RK818_ID_BOOST,
+	RK818_ID_LDO1,
+	RK818_ID_LDO2,
+	RK818_ID_LDO3,
+	RK818_ID_LDO4,
+	RK818_ID_LDO5,
+	RK818_ID_LDO6,
+	RK818_ID_LDO7,
+	RK818_ID_LDO8,
+	RK818_ID_LDO9,
+	RK818_ID_SWITCH,
+	RK818_ID_HDMI_SWITCH,
+	RK818_ID_OTG_SWITCH,
+};
+
+#define RK818_DCDC_EN_REG		0x23
+#define RK818_LDO_EN_REG		0x24
+#define RK818_SLEEP_SET_OFF_REG1	0x25
+#define RK818_SLEEP_SET_OFF_REG2	0x26
+#define RK818_DCDC_UV_STS_REG		0x27
+#define RK818_DCDC_UV_ACT_REG		0x28
+#define RK818_LDO_UV_STS_REG		0x29
+#define RK818_LDO_UV_ACT_REG		0x2a
+#define RK818_DCDC_PG_REG		0x2b
+#define RK818_LDO_PG_REG		0x2c
+#define RK818_VOUT_MON_TDB_REG		0x2d
+#define RK818_BUCK1_CONFIG_REG		0x2e
+#define RK818_BUCK1_ON_VSEL_REG		0x2f
+#define RK818_BUCK1_SLP_VSEL_REG	0x30
+#define RK818_BUCK2_CONFIG_REG		0x32
+#define RK818_BUCK2_ON_VSEL_REG		0x33
+#define RK818_BUCK2_SLP_VSEL_REG	0x34
+#define RK818_BUCK3_CONFIG_REG		0x36
+#define RK818_BUCK4_CONFIG_REG		0x37
+#define RK818_BUCK4_ON_VSEL_REG		0x38
+#define RK818_BUCK4_SLP_VSEL_REG	0x39
+#define RK818_BOOST_CONFIG_REG		0x3a
+#define RK818_LDO1_ON_VSEL_REG		0x3b
+#define RK818_LDO1_SLP_VSEL_REG		0x3c
+#define RK818_LDO2_ON_VSEL_REG		0x3d
+#define RK818_LDO2_SLP_VSEL_REG		0x3e
+#define RK818_LDO3_ON_VSEL_REG		0x3f
+#define RK818_LDO3_SLP_VSEL_REG		0x40
+#define RK818_LDO4_ON_VSEL_REG		0x41
+#define RK818_LDO4_SLP_VSEL_REG		0x42
+#define RK818_LDO5_ON_VSEL_REG		0x43
+#define RK818_LDO5_SLP_VSEL_REG		0x44
+#define RK818_LDO6_ON_VSEL_REG		0x45
+#define RK818_LDO6_SLP_VSEL_REG		0x46
+#define RK818_LDO7_ON_VSEL_REG		0x47
+#define RK818_LDO7_SLP_VSEL_REG		0x48
+#define RK818_LDO8_ON_VSEL_REG		0x49
+#define RK818_LDO8_SLP_VSEL_REG		0x4a
+#define RK818_BOOST_LDO9_ON_VSEL_REG	0x54
+#define RK818_BOOST_LDO9_SLP_VSEL_REG	0x55
+#define RK818_DEVCTRL_REG		0x4b
+#define RK818_INT_STS_REG1		0X4c
+#define RK818_INT_STS_MSK_REG1		0x4d
+#define RK818_INT_STS_REG2		0x4e
+#define RK818_INT_STS_MSK_REG2		0x4f
+#define RK818_IO_POL_REG		0x50
+#define RK818_H5V_EN_REG		0x52
+#define RK818_SLEEP_SET_OFF_REG3	0x53
+#define RK818_BOOST_LDO9_ON_VSEL_REG	0x54
+#define RK818_BOOST_LDO9_SLP_VSEL_REG	0x55
+#define RK818_BOOST_CTRL_REG		0x56
+#define RK818_DCDC_ILMAX		0x90
+#define RK818_USB_CTRL_REG		0xa1
+
+#define RK818_H5V_EN			BIT(0)
+#define RK818_REF_RDY_CTRL		BIT(1)
+#define RK818_USB_ILIM_SEL_MASK		0xf
+#define RK818_USB_ILMIN_2000MA		0x7
+#define RK818_USB_CHG_SD_VSEL_MASK	0x70
+
+/* RK808 IRQ Definitions */
 #define RK808_IRQ_VOUT_LO	0
 #define RK808_IRQ_VB_LO		1
 #define RK808_IRQ_PWRON		2
@@ -137,6 +226,43 @@ enum rk808_reg {
 #define RK808_IRQ_PLUG_IN_INT_MSK	BIT(0)
 #define RK808_IRQ_PLUG_OUT_INT_MSK	BIT(1)
 
+/* RK818 IRQ Definitions */
+#define RK818_IRQ_VOUT_LO	0
+#define RK818_IRQ_VB_LO		1
+#define RK818_IRQ_PWRON		2
+#define RK818_IRQ_PWRON_LP	3
+#define RK818_IRQ_HOTDIE	4
+#define RK818_IRQ_RTC_ALARM	5
+#define RK818_IRQ_RTC_PERIOD	6
+#define RK818_IRQ_USB_OV	7
+#define RK818_IRQ_PLUG_IN	8
+#define RK818_IRQ_PLUG_OUT	9
+#define RK818_IRQ_CHG_OK	10
+#define RK818_IRQ_CHG_TE	11
+#define RK818_IRQ_CHG_TS1	12
+#define RK818_IRQ_TS2		13
+#define RK818_IRQ_CHG_CVTLIM	14
+#define RK818_IRQ_DISCHG_ILIM	7
+
+#define RK818_IRQ_VOUT_LO_MSK		BIT(0)
+#define RK818_IRQ_VB_LO_MSK		BIT(1)
+#define RK818_IRQ_PWRON_MSK		BIT(2)
+#define RK818_IRQ_PWRON_LP_MSK		BIT(3)
+#define RK818_IRQ_HOTDIE_MSK		BIT(4)
+#define RK818_IRQ_RTC_ALARM_MSK		BIT(5)
+#define RK818_IRQ_RTC_PERIOD_MSK	BIT(6)
+#define RK818_IRQ_USB_OV_MSK		BIT(7)
+#define RK818_IRQ_PLUG_IN_MSK		BIT(0)
+#define RK818_IRQ_PLUG_OUT_MSK		BIT(1)
+#define RK818_IRQ_CHG_OK_MSK		BIT(2)
+#define RK818_IRQ_CHG_TE_MSK		BIT(3)
+#define RK818_IRQ_CHG_TS1_MSK		BIT(4)
+#define RK818_IRQ_TS2_MSK		BIT(5)
+#define RK818_IRQ_CHG_CVTLIM_MSK	BIT(6)
+#define RK818_IRQ_DISCHG_ILIM_MSK	BIT(7)
+
+#define RK818_NUM_IRQ		16
+
 #define RK808_VBAT_LOW_2V8	0x00
 #define RK808_VBAT_LOW_2V9	0x01
 #define RK808_VBAT_LOW_3V0	0x02
@@ -191,9 +317,27 @@ enum {
 	BOOST_ILMIN_250MA,
 };
 
+enum {
+	RK808_ID,
+	RK818_ID,
+};
+
+struct rk8xx_reg_data {
+	int addr;
+	int mask;
+	int value;
+};
+
 struct rk808 {
-	struct i2c_client *i2c;
-	struct regmap_irq_chip_data *irq_data;
-	struct regmap *regmap;
+	struct i2c_client		*i2c;
+	struct regmap_irq_chip_data	*irq_data;
+	struct regmap			*regmap;
+	long				variant;
+	int				nr_cells;
+	const struct mfd_cell		*cells;
+	const struct regmap_config	*regmap_cfg;
+	const struct regmap_irq_chip	*regmap_irq_chip;
+	const struct rk8xx_reg_data	*pre_init_reg;
+	int				nr_pre_init_regs;
 };
-#endif /* __LINUX_REGULATOR_rk808_H */
+#endif /* __LINUX_REGULATOR_RK808_H */
-- 
1.9.1



From w.egorov at phytec.de  Tue May 10 06:18:59 2016
From: w.egorov at phytec.de (Wadim Egorov)
Date: Tue, 10 May 2016 15:18:59 +0200
Subject: [PATCH v5 5/6] clk: Kconfig: Name RK818 in Kconfig for
 COMMON_CLK_RK808
In-Reply-To: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
References: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
Message-ID: <1462886340-7893-6-git-send-email-w.egorov@phytec.de>

The RK808 and RK818 PMICs are using a similar register map.
We can reuse the clk driver for the RK818 PMIC. So let's add
the RK818 in the Kconfig description.

Signed-off-by: Wadim Egorov <w.egorov at phytec.de>
Acked-by: Stephen Boyd <sboyd at codeaurora.org>
---
 drivers/clk/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
index 2dd371d..af10f2a 100644
--- a/drivers/clk/Kconfig
+++ b/drivers/clk/Kconfig
@@ -49,10 +49,10 @@ config COMMON_CLK_MAX77802
 	  This driver supports Maxim 77802 crystal oscillator clock.
 
 config COMMON_CLK_RK808
-	tristate "Clock driver for RK808"
+	tristate "Clock driver for RK808/RK818"
 	depends on MFD_RK808
 	---help---
-	  This driver supports RK808 crystal oscillator clock. These
+	  This driver supports RK808 and RK818 crystal oscillator clock. These
 	  multi-function devices have two fixed-rate oscillators,
 	  clocked at 32KHz each. Clkout1 is always on, Clkout2 can off
 	  by control register.
-- 
1.9.1



From w.egorov at phytec.de  Tue May 10 06:19:00 2016
From: w.egorov at phytec.de (Wadim Egorov)
Date: Tue, 10 May 2016 15:19:00 +0200
Subject: [PATCH v5 6/6] rtc: Kconfig: Name RK818 in Kconfig for RTC_DRV_RK808
In-Reply-To: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
References: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
Message-ID: <1462886340-7893-7-git-send-email-w.egorov@phytec.de>

The RK808 and RK818 PMICs are using a similar register map.
We can reuse the rtc driver for the RK818 PMIC. So let's add
the RK818 in the Kconfig description.

Signed-off-by: Wadim Egorov <w.egorov at phytec.de>
Acked-by: Alexandre Belloni <alexandre.belloni at free-electrons.com>
---
 drivers/rtc/Kconfig | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 18639e0..2faed74 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -324,11 +324,11 @@ config RTC_DRV_MAX77686
 	  will be called rtc-max77686.
 
 config RTC_DRV_RK808
-	tristate "Rockchip RK808 RTC"
+	tristate "Rockchip RK808/RK818 RTC"
 	depends on MFD_RK808
 	help
 	  If you say yes here you will get support for the
-	  RTC of RK808 PMIC.
+	  RTC of RK808 and RK818 PMIC.
 
 	  This driver can also be built as a module. If so, the module
 	  will be called rk808-rtc.
-- 
1.9.1



From arnd at arndb.de  Tue May 10 06:39:03 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 10 May 2016 15:39:03 +0200
Subject: [GIT PULL 2/3] Rockchip dts32 updates for v4.7 - part2
In-Reply-To: <76948175.MyD0mx7K4Q@diego>
References: <5544434.9tA8JHBIkp@diego> <76948175.MyD0mx7K4Q@diego>
Message-ID: <2872722.0tBjL4e5JT@wuerfel>

On Friday 29 April 2016 00:24:48 Heiko St?bner wrote:
> This adds the rk3288-miqi as new board, adapts the edp-phy settings
> to the binding-change that made it into 4.6, adds rk3288 i2c controller
> nodes and moves the rk3288 thermal data into the soc dtsi, as there
> really is no need to have that separate file.
> 

Pulled into next/dt, thanks!

	Arnd


From lee.jones at linaro.org  Tue May 10 07:03:20 2016
From: lee.jones at linaro.org (Lee Jones)
Date: Tue, 10 May 2016 15:03:20 +0100
Subject: [PATCH v5 3/6] regulator: rk808: Add regulator driver for RK818
In-Reply-To: <1462886340-7893-4-git-send-email-w.egorov@phytec.de>
References: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
 <1462886340-7893-4-git-send-email-w.egorov@phytec.de>
Message-ID: <20160510140320.GO19473@dell>

On Tue, 10 May 2016, Wadim Egorov wrote:

> Add support for the rk818 regulator. The regulator module consists
> of 4 DCDCs, 9 LDOs, 1 switch and 1 BOOST converter which is used to
> power OTG and HDMI5V.
> 
> The output voltages are configurable and are meant to supply power
> to the main processor and other components.
> 
> Signed-off-by: Wadim Egorov <w.egorov at phytec.de>
> ---
>  drivers/regulator/Kconfig           |   4 +-
>  drivers/regulator/rk808-regulator.c | 143 ++++++++++++++++++++++++++++++++++--
>  2 files changed, 138 insertions(+), 9 deletions(-)

Needs an Ack before I can take the set.

-- 
Lee Jones
Linaro STMicroelectronics Landing Team Lead
Linaro.org ? Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog


From w.egorov at phytec.de  Tue May 10 07:15:23 2016
From: w.egorov at phytec.de (Wadim Egorov)
Date: Tue, 10 May 2016 16:15:23 +0200
Subject: [PATCH v5 3/6] regulator: rk808: Add regulator driver for RK818
In-Reply-To: <20160510140320.GO19473@dell>
References: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
 <1462886340-7893-4-git-send-email-w.egorov@phytec.de>
 <20160510140320.GO19473@dell>
Message-ID: <5731ECFB.2000207@phytec.de>



On 10.05.2016 16:03, Lee Jones wrote:
> On Tue, 10 May 2016, Wadim Egorov wrote:
>
>> Add support for the rk818 regulator. The regulator module consists
>> of 4 DCDCs, 9 LDOs, 1 switch and 1 BOOST converter which is used to
>> power OTG and HDMI5V.
>>
>> The output voltages are configurable and are meant to supply power
>> to the main processor and other components.
>>
>> Signed-off-by: Wadim Egorov <w.egorov at phytec.de>
>> ---
>>  drivers/regulator/Kconfig           |   4 +-
>>  drivers/regulator/rk808-regulator.c | 143 ++++++++++++++++++++++++++++++++++--
>>  2 files changed, 138 insertions(+), 9 deletions(-)
> Needs an Ack before I can take the set.
>

Mark acked this patch in v3.
After small changes I removed the ack again. I don't know if it is ok to
keep an Acked-by with small changes in the patch.


From john at metanate.com  Tue May 10 08:50:46 2016
From: john at metanate.com (John Keeping)
Date: Tue, 10 May 2016 16:50:46 +0100
Subject: [PATCH] iommu/rockchip: fix zap cache during device attach
Message-ID: <20160510155046.24515-1-john@metanate.com>

rk_iommu_command() takes a struct rk_iommu and iterates over the slave
MMUs, so this is doubly wrong in that we're passing in the wrong pointer
and talking to MMUs that we shouldn't be.

Fixes: cd6438c5f844 ("iommu/rockchip: Reconstruct to support multi slaves")
Signed-off-by: John Keeping <john at metanate.com>
---
 drivers/iommu/rockchip-iommu.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 5710a06c3049..0ea8d9a24de0 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -815,7 +815,7 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
 	dte_addr = virt_to_phys(rk_domain->dt);
 	for (i = 0; i < iommu->num_mmu; i++) {
 		rk_iommu_write(iommu->bases[i], RK_MMU_DTE_ADDR, dte_addr);
-		rk_iommu_command(iommu->bases[i], RK_MMU_CMD_ZAP_CACHE);
+		rk_iommu_base_command(iommu->bases[i], RK_MMU_CMD_ZAP_CACHE);
 		rk_iommu_write(iommu->bases[i], RK_MMU_INT_MASK, RK_MMU_IRQ_MASK);
 	}
 
-- 
2.8.2.565.gdb84f68.dirty



From dianders at chromium.org  Tue May 10 08:57:03 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 10 May 2016 08:57:03 -0700
Subject: [PATCH 2/2] dt-bindings: rockchip-dw-mshc: add rockchip,
 default-drv-phase
In-Reply-To: <1f2f43c7-2672-e448-eddb-2d613bb8dc48@rock-chips.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
 <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=WSkBwBjVsRoDsfjD+sNfR70mKGRA0khjPKKW0zS2=PTw@mail.gmail.com>
 <b15dcb4f-1584-8219-2fe0-97eecb0c64a6@rock-chips.com>
 <CAD=FV=XToSzqSh=SShHuQU9W_m7gfyQn8wRXkLy79t+tnqZknA@mail.gmail.com>
 <1f2f43c7-2672-e448-eddb-2d613bb8dc48@rock-chips.com>
Message-ID: <CAD=FV=UGbrJRyUbbgzbcYf9GjPG+Fh_gpQ3rX2G=wi2w5Lw=Sg@mail.gmail.com>

(again, but not HTML)

On Tue, May 10, 2016 at 3:19 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> ? 2016/5/10 0:31, Doug Anderson ??:
>>
>> Hi,
>>
>> On Mon, May 9, 2016 at 4:12 AM, Shawn Lin <shawn.lin at rock-chips.com>
>> wrote:
>>>>
>>>> 1. Specifying a single number for this property in terms of "degrees"
>>>> is probably not right.  The whole point of setting the "drive phase"
>>>> is to meet hold times, which are specified in the spec in terms of ns
>>>> in the spec and also specified differently for different SD/MMC speed
>>>> modes.  Note also that "phase" translates to very different delays (in
>>>> terms of ns) depending on the clock rate:
>>>>
>>>> At 400 kHz, period is 2.5 us, so 90 degree phase offset is a delay of
>>>> 625
>>>> ns
>>>> At 25 MHz, period is 40 ns, so a 90 degree phase offset represents a
>>>> delay of 10 ns.
>>>> At 50 MHz, period is 20 ns, so a 90 degree phase offset represents a
>>>> delay of 5 ns.
>>>> At 200 MHz, period is period is 5 ns, so a 90 degree phase offset
>>>> represents a delay of 1.25 ns.
>>>
>>>
>>>
>>> yes, if we use degrees only(0/90/180/270), the timing is always right.
>>> But considering the delay number, we need to do some crazy calculation
>>> in the set_ios callback.
>>
>>
>> Great, so let's limit it to 0/90/180/270 for the drive phase offset.
>> We don't need lots of precision for the drive phase offset (right?)
>> and accuracy is more important.
>
>
> yes.
>
>>
>>
>>>> 2. As I understand it, the value needed for the drive phase is not
>>>> board specific unless you've got super crazy layout on a board (where
>>>> the clock line takes a very different path than everything else).
>>>> It's also not even terribly SoC-specific unless you've got some very
>>>> strange incarnation of dw_mmc that has very different internal delays
>>>> than everyone else.  Said another way, until we see an instance of an
>>>> SoC/board that really needs to do things special I'd say that we
>>>> should just implement this all in code (no device tree bindings).
>>>>
>>>
>>> I'm prone to think it should be Soc specific if making sure the layout
>>> for data lines is in equal length.
>>
>>
>> Sure, it can be SoC specific.  ...though at the moment, I'd bet that
>> you can come up with a single rule for the drive phase offset that
>> will work for every Rockchip SoC produced so far, especially if you
>> are using only 0/90/180/270.  I'd imagine that they all have similar
>> enough internal delays.
>
>
> For a specific Soc, it's the basic rule to make sure the internal delays
> is the same(nearly the same) for all of the lines.

Right.  I was saying that not only are all lines within a given SoC
similar in terms of delay, but I was suggesting that perhaps the
internal delay for rk3188, rk3288, rk3228, ... is probably fairly
similar.  That's only a guess, though.


>>>> 3. If this property was actually board specific and actually needed to
>>>> be tuned board-by-board, you'd have a bug because your new device tree
>>>> bindings are not backward compatible and you'd probably be breaking
>>>> old boards.  Specifically you're changing the definition of what
>>>> happens when "rockchip,default-drv-phase" is not specified.  Old
>>>> behavior was to leave the value that was setup by the firmware (or
>>>> perhaps the hardware default if the firmware didn't touch this).
>>>
>>>
>>>
>>> drv_phase is for all the data lines instead of tuning the lines
>>> one-by-one. So this patch can't save the terrible board layout.
>>> But I agree that it will break the compatibility backward if firware
>>> touch this value.
>>>
>>>>
>>>> ---
>>>>
>>>> OK, so what should we do?
>>>>
>>>> We could certainly do lots of crazy math to come up with the ideal
>>>> hold time for all different speed modes and all different types of
>>>> cards.  With my reading of the Designware Databook this would mean
>>>> that somewhere we'd want to specify which delay method we're using
>>>> (phase shift vs. delay line) and how long all the delays timings all
>>>> are on your particular SoC.  That all sounds quite difficult, though.
>>>
>>>
>>>
>>> delay line is diff from chip to chip, soc-to-soc, board-to-board. For
>>> sample-phase we have tuning process and re-tune, but not for drv-phase.
>>> So We bascially should avoid to use it for drv-phase. Another
>>> consideration is the temperature drift of delay line.
>>>
>>> Maybe we should do some tricky limitation on clk-mmc-phase to only
>>> support fixed degrees?
>>
>>
>> As per above, let's not use delay line for drive delay.  On all
>> Rockchip SoCs that I have seen it's possible to make 0/90/180/270 very
>> accurately.  That means no board-to-board differences.  Current
>> mainline Linux kernel source code will always make 0/90/180/270 using
>> phase offset (not delay line).
>
>
> yes, 0/90/180/270 is very accurate and mainline kernel use phase offset
> for these four phase.
>
>>
>> For sampling we use tuning and using the delay elements makes some
>> sense (since 90 degrees is not quite accurate enough to fully tune
>> UHS).  ...but for driving where the only requirement is hold times we
>> don't need delay elements.
>
>
> Right. We care hold time here.
>
>>
>>
>>>> Probably you could just add a simple function that looked at the clock
>>>> and speed mode and always chose an offset of 90 or 180 degrees.  At
>>>> least on Rockchip devices you can be certain that you can make 90 and
>>>> 180 degrees using phase shifts and thus the timings should be
>>>> consistent.  By default you could just always choose 180.  The
>>>> Designware databook has some examples where it picked 90 degrees
>>>> (SDR50, DDR50, SDR25, MMC High Speed), but I'm not enough of an MMC
>>>> expert to know if there is some benefit to choosing 90.  Would we
>>>> violate any specs if we just chose 180 degrees all the time everywhere
>>>> on all Rockchip devices?
>>>
>>>
>>>
>>> It needs more waveform test to see how things going. But most of
>>> rockchip platforms in the pass years didn't touch drv-phase stuff not
>>> only in kernel but also in firmware, then we still cannot see the
>>> violation against the spec when using defalut reset value, namely 180,
>>> for
>>> drv-phase.
>>
>>
>> Right, most Rockchip platforms simply don't touch this and it works
>> OK.  ...but I don't think it defaults to 180.  Grepping through on my
>> veyron (rk3288) device shows
>>
>>        sdio1_drv - 90
>>        sdio0_drv - 90
>>        sdmmc_drv - 90
>>        emmc_drv -180
>>
>> ...and, as we've seen, these values appear to be 270 on some other SoCs.
>>
>
> Have your code touched them? I check the TRM and find it should be 180
> always.
>
> Also for rk3036/3368/3399/3228.... the reset vaule is 180...

I have less faith than you in the TRM.  The TRM is full of minor
errors and is often wrong about the default state of things.  IMHO the
only true way to find out is to boot up some SoCs and check.

As far as whether code touches these values:

* I'm 100% certain that the kernel on rk3288 I tested doesn't touch.

* I'm 100% certain that the kernel on rk3399 I tested doesn't touch.

* I'm 95% certain that the BIOS (coreboot/depthcharge) on rk3288 I
tested doesn't touch.

* I'm 95% certain that the BIOS (coreboot/depthcharge) on rk3399 I
tested doesn't touch.  Note that the TRM on rk3399 does say 180
degrees is the default, but I believe you have also verified that it
comes up as 270.  Have you found any reason for this?


Also note that I look at V1.1 of the rk3288 TRM in the CRU section and I see:

* CRU_SDMMC_CON0: drive degree defaults to 0x1
* CRU_SDIO0_CON0: drive degree defaults to 0x1
* CRU_SDIO1_CON0: drive degree defaults to 0x1
* CRU_EMMC_CON0: drive degree defaults to 0x1

That actually means that they default to 90.  Of course you can also
see that the TRM is probably flawed because it claims that all the
bits here are "WO" (write only).  They are clearly not.

The TRM is also internally inconsistent.  When I then go into the
Mobile Storage Host section (Variable Delay/Clock Generation), I see
that it does in fact claim that the default is 180.


>> The claim from the Designware Databook says that SDR104 and SDR12, and
>> identification mode need 180 degrees to work properly.  It would be
>> interesting to hook up rk3288 to a signal analyzer and see hold times
>> are OK or if we need to move up to 180 degrees for those modes.
>>
>> Note that the Designware Databook assumes "Delay_O" of 1.4ns.  If
>> yours is shorter then maybe 90 degrees is OK for those modes?
>>
>
> maybe. But I think 180(downside) is the better.

I'm OK with using 180 always as long as SD cards continue to work OK.
Best would be if someone could actually run a protocol analyzer for
all the different speed modes.


>> Also: I still haven't heard whether there is any downside to using 180
>> degrees for modes that only require 90 degrees.  Does it cause
>> problems to just always use 180 degrees?  If not, we could possibly
>> use 180 degrees everywhere and just hardcode it?
>
>
> From tons of test on rockchip products which always use 180, I didn't
> see failure. Hardcoding it doesn't look so decent maybe... but anyway
> it works.

Hardcoding in this case is much better than putting in a device tree
binding.  I'm nearly certain that having a device tree binding that
doesn't account for different clock rates / speed modes is not a good
idea, and device tree bindings are supposed to be "set in stone".
Let's just hardcode it for now.

I can post up a CL.


>> ...but if 180 is ideal everywhere, can you answer:
>>
>> * Why does dw_mmc manual spend so much time talking about it?  It
>> could just say "set to 180 degrees".
>
>
> I'm sure all the rockchip Socs defaultly use 180 for drv_phase if I got
> the right TRMs these years.
>
> Anyway let me check it with my ASIC team and I will let you know
> the result.

You probably have the right TRMs.  The TRMs are just not accurate.  ;)


From john at metanate.com  Tue May 10 09:03:53 2016
From: john at metanate.com (John Keeping)
Date: Tue, 10 May 2016 17:03:53 +0100
Subject: [PATCH 0/3] drm/rockchip: fix some sparse warnings
Message-ID: <20160510160356.1167-1-john@metanate.com>

The first patch wasn't found by sparse, but is something I noticed while
in the area.  The following two fix all of the sparse warnings inside
drm/rockchip.

John Keeping (3):
  drm/rockchip: dw_hdmi: remove unused #include
  drm/rockchip: fb: add missing header
  drm/rockchip: fix "should it be static?" warnings

 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 -
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 ++--
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  | 7 ++++---
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 ++--
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 +-
 5 files changed, 9 insertions(+), 9 deletions(-)

-- 
2.8.2.565.gdb84f68.dirty



From john at metanate.com  Tue May 10 09:03:54 2016
From: john at metanate.com (John Keeping)
Date: Tue, 10 May 2016 17:03:54 +0100
Subject: [PATCH 1/3] drm/rockchip: dw_hdmi: remove unused #include
In-Reply-To: <20160510160356.1167-1-john@metanate.com>
References: <20160510160356.1167-1-john@metanate.com>
Message-ID: <20160510160356.1167-2-john@metanate.com>

drm_encoder_slave is not used in this file.

Signed-off-by: John Keeping <john at metanate.com>
---
 drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
index 801110f65a63..0665fb915579 100644
--- a/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
+++ b/drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c
@@ -15,7 +15,6 @@
 #include <drm/drmP.h>
 #include <drm/drm_crtc_helper.h>
 #include <drm/drm_edid.h>
-#include <drm/drm_encoder_slave.h>
 #include <drm/bridge/dw_hdmi.h>
 
 #include "rockchip_drm_drv.h"
-- 
2.8.2.565.gdb84f68.dirty



From john at metanate.com  Tue May 10 09:03:55 2016
From: john at metanate.com (John Keeping)
Date: Tue, 10 May 2016 17:03:55 +0100
Subject: [PATCH 2/3] drm/rockchip: fb: add missing header
In-Reply-To: <20160510160356.1167-1-john@metanate.com>
References: <20160510160356.1167-1-john@metanate.com>
Message-ID: <20160510160356.1167-3-john@metanate.com>

This fixes the following sparse warnings:

drivers/gpu/drm/rockchip/rockchip_drm_fb.c:32:23: warning: symbol 'rockchip_fb_get_gem_obj' was not declared. Should it be static?
drivers/gpu/drm/rockchip/rockchip_drm_fb.c:315:24: warning: symbol 'rockchip_drm_framebuffer_init' was not declared. Should it be static?
drivers/gpu/drm/rockchip/rockchip_drm_fb.c:329:6: warning: symbol 'rockchip_drm_mode_config_init' was not declared. Should it be static?

Signed-off-by: John Keeping <john at metanate.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 8c10163a95bc..85aa87ee12f5 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -20,6 +20,7 @@
 #include <drm/drm_crtc_helper.h>
 
 #include "rockchip_drm_drv.h"
+#include "rockchip_drm_fb.h"
 #include "rockchip_drm_gem.h"
 
 #define to_rockchip_fb(x) container_of(x, struct rockchip_drm_fb, fb)
-- 
2.8.2.565.gdb84f68.dirty



From john at metanate.com  Tue May 10 09:03:56 2016
From: john at metanate.com (John Keeping)
Date: Tue, 10 May 2016 17:03:56 +0100
Subject: [PATCH 3/3] drm/rockchip: fix "should it be static?" warnings
In-Reply-To: <20160510160356.1167-1-john@metanate.com>
References: <20160510160356.1167-1-john@metanate.com>
Message-ID: <20160510160356.1167-4-john@metanate.com>

Combined with the previous commit, this fixes all of the sparse warnings
in drm/rockchip.

Signed-off-by: John Keeping <john at metanate.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 ++--
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  | 6 +++---
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 ++--
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 +-
 4 files changed, 8 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
index 399adf3c4224..b253f65c3e14 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
@@ -287,7 +287,7 @@ static void rockchip_drm_preclose(struct drm_device *dev,
 		rockchip_drm_crtc_cancel_pending_vblank(crtc, file_priv);
 }
 
-void rockchip_drm_lastclose(struct drm_device *dev)
+static void rockchip_drm_lastclose(struct drm_device *dev)
 {
 	struct rockchip_drm_private *priv = dev->dev_private;
 
@@ -307,7 +307,7 @@ static const struct file_operations rockchip_drm_driver_fops = {
 	.release = drm_release,
 };
 
-const struct vm_operations_struct rockchip_drm_vm_ops = {
+static const struct vm_operations_struct rockchip_drm_vm_ops = {
 	.open = drm_gem_vm_open,
 	.close = drm_gem_vm_close,
 };
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 85aa87ee12f5..96d91f16e001 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -275,9 +275,9 @@ void rockchip_drm_atomic_work(struct work_struct *work)
 	rockchip_atomic_commit_complete(commit);
 }
 
-int rockchip_drm_atomic_commit(struct drm_device *dev,
-			       struct drm_atomic_state *state,
-			       bool nonblock)
+static int rockchip_drm_atomic_commit(struct drm_device *dev,
+				      struct drm_atomic_state *state,
+				      bool nonblock)
 {
 	struct rockchip_drm_private *private = dev->dev_private;
 	struct rockchip_atomic_commit *commit = &private->commit;
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index bf55cda356ba..949171a80631 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -779,7 +779,7 @@ static const struct drm_plane_helper_funcs plane_helper_funcs = {
 	.atomic_disable = vop_plane_atomic_disable,
 };
 
-void vop_atomic_plane_reset(struct drm_plane *plane)
+static void vop_atomic_plane_reset(struct drm_plane *plane)
 {
 	struct vop_plane_state *vop_plane_state =
 					to_vop_plane_state(plane->state);
@@ -796,7 +796,7 @@ void vop_atomic_plane_reset(struct drm_plane *plane)
 	plane->state->plane = plane;
 }
 
-struct drm_plane_state *
+static struct drm_plane_state *
 vop_atomic_plane_duplicate_state(struct drm_plane *plane)
 {
 	struct vop_plane_state *old_vop_plane_state;
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 3166b46a5893..52661d116ec2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -299,7 +299,7 @@ static int vop_remove(struct platform_device *pdev)
 	return 0;
 }
 
-struct platform_driver vop_platform_driver = {
+static struct platform_driver vop_platform_driver = {
 	.probe = vop_probe,
 	.remove = vop_remove,
 	.driver = {
-- 
2.8.2.565.gdb84f68.dirty



From dianders at chromium.org  Tue May 10 11:16:35 2016
From: dianders at chromium.org (Douglas Anderson)
Date: Tue, 10 May 2016 11:16:35 -0700
Subject: [PATCH] mmc: dw_mmc: rockchip: Set the drive phase to 180 degrees
Message-ID: <1462904195-18229-1-git-send-email-dianders@chromium.org>

Historically for Rockchip devices we've relied on the power-on
default (or perhaps the firmware setting) to get the correct drive
phase for dw_mmc devices.  This worked OK for the most part, but:

* Relying on the setting just "being right" is a bit fragile.

* As soon as there is an instance where the power on default is wrong or
  where the firmware didn't configure this properly then we'll get a
  mysterious failure.

Let's explicitly set this phase in the kernel.

You might notice that this patch is currently very dumb and just always
sets this phase to 180 degrees.  As far as I can tell this is actually a
sane thing to do.  From reading through the Designware Databook it
appears that there are instances where you could still meet hold time
requirements and set this phase to 90 degrees, but nothing I've read
indicates that 180 degrees is not OK also.

As indicated above, adding a delay to the drive is used to achieve
proper hold times.  For a given speed mode hold times are listed in the
spec in terms of nanoseconds.  The hold times are different for
different speed modes.  The actual hold time achieved is actually a
function of Delay_O (an internal delay in dw_mmc, which could vary from
SoC model to SoC model), pad delays, and the drive delay (which we're
setting here).  Note also that by setting the drive delay as a phase we
will get a different number of nanoseconds of delay depending on the
input clock.

Note that, as far as I can tell, this _does_ change the behavior of
rk3288 devices.  On devices I tested, which use coreboot/depthcharge as
BIOS, the SDMMC/SDIO0/SDIO1 drive phase used to be 90 degrees.  Now it
will be 180 degrees.  With my understanding from the Designware Databook
the 180 degrees ought to be more correct and should increase
compatibility.

I have tested this by inserting my collection of uSD cards (mostly UHS,
though a few not) into a veyron_minnie and confirmed that they still
seem to enumerate properly.  For a subset of them I tried putting a
filesystem on them and also tried running mmc_test.

Signed-off-by: Douglas Anderson <dianders at chromium.org>
---
 drivers/mmc/host/dw_mmc-rockchip.c | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 8c20b81cafd8..62cbd33a07cd 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -66,6 +66,27 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 	/* Make sure we use phases which we can enumerate with */
 	if (!IS_ERR(priv->sample_clk))
 		clk_set_phase(priv->sample_clk, priv->default_sample_phase);
+
+	/*
+	 * Set the drive phase to 180 degrees.  This helps us achieve proper
+	 * hold times.
+	 *
+	 * Note that this is _not_ a value that is tuned and is also _not_ a
+	 * value that will vary from board to board.  It is a value that
+	 * _could_ vary between different SoC models (could be different on
+	 * rk3066 vs. rk3288 for instance).  It is also a value that _could_
+	 * need to be adjusted based on our clock frequency and speed mode
+	 * since different speed modes have different hold time requirements
+	 * and hold time requirements are in "ns" (a phase offset adds a
+	 * different "ns" delay for different input clocks).
+	 *
+	 * Despite these theoretical needs, it has been observed that 180
+	 * degrees gives us good signaling across all tested SoCs and all
+	 * tested speed modes.  If when we find someone that needs 90 degrees
+	 * here we can add a table based on speed mode / SoC compatible ID.
+	 */
+	if (!IS_ERR(priv->drv_clk))
+		clk_set_phase(priv->drv_clk, 180);
 }
 
 #define NUM_PHASES			360
-- 
2.8.0.rc3.226.g39d4020



From broonie at kernel.org  Tue May 10 11:49:56 2016
From: broonie at kernel.org (Mark Brown)
Date: Tue, 10 May 2016 19:49:56 +0100
Subject: Applied "ASoC: rockchip-max98090: Fix jack detection and event
 reporting." to the asoc tree
In-Reply-To: <1462790795-25345-4-git-send-email-enric.balletbo@collabora.com>
Message-ID: <E1b0CjE-0008Nv-EN@debutante>

The patch

   ASoC: rockchip-max98090: Fix jack detection and event reporting.

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 525aba92762666aa6fa56e1b92e7d4959bda426a Mon Sep 17 00:00:00 2001
From: Enric Balletbo i Serra <enric.balletbo at collabora.com>
Date: Mon, 9 May 2016 12:46:33 +0200
Subject: [PATCH] ASoC: rockchip-max98090: Fix jack detection and event
 reporting.

Physically there is a jackset which includes a Headphone and a Jackset
Mic pin. The patch add thw two pins with the correct pin name so the
DAPM management can find the pin and make the jack detection and event
reporting work again.

The patch also shut up the following error:

 rockchip-snd-max98090 sound: ASoC: DAPM unknown pin Headset Jack

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/rockchip/rockchip_max98090.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index 3da7891b7dfb..e70ffad07184 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -34,13 +34,18 @@
 #define DRV_NAME "rockchip-snd-max98090"
 
 static struct snd_soc_jack headset_jack;
+
+/* Headset jack detection DAPM pins */
 static struct snd_soc_jack_pin headset_jack_pins[] = {
 	{
-		.pin = "Headset Jack",
-		.mask = SND_JACK_HEADPHONE | SND_JACK_MICROPHONE |
-			SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-			SND_JACK_BTN_2 | SND_JACK_BTN_3,
+		.pin = "Headphone",
+		.mask = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin = "Headset Mic",
+		.mask = SND_JACK_MICROPHONE,
 	},
+
 };
 
 static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
-- 
2.8.1



From broonie at kernel.org  Tue May 10 11:50:02 2016
From: broonie at kernel.org (Mark Brown)
Date: Tue, 10 May 2016 19:50:02 +0100
Subject: Applied "ASoC: rockchip-max98090: Fix NULL pointer dereference while
 accessing to jack." to the asoc tree
In-Reply-To: <1462435421-21205-4-git-send-email-enric.balletbo@collabora.com>
Message-ID: <E1b0CjK-00007p-Fj@debutante>

The patch

   ASoC: rockchip-max98090: Fix NULL pointer dereference while accessing to jack.

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From af637e3adaf538288cbb3e6a2d9a4059853fc15a Mon Sep 17 00:00:00 2001
From: Enric Balletbo i Serra <enric.balletbo at collabora.com>
Date: Mon, 9 May 2016 12:46:31 +0200
Subject: [PATCH] ASoC: rockchip-max98090: Fix NULL pointer dereference while
 accessing to jack.

Commit f2ed6b07645e ("ASoC: Make aux_dev more like a generic
component") caused a regression on this driver, since now a
kernel oops is seen when rockchip-mac98090 driver is loaded.

That commit changed the probing of aux_devs before checking
new DAI links, so for this driver rk_98090_headset_init is
called before rk_init and then the kernel oops due a NULL
pointer dereference inside rk_98090_headset_init function
since there is a call that tries to access the jack pointer
which has not been allocated yet.

This is the call chain that causes the crash:

 rk_98090_headset_init
   -> ts3a227e_enable_jack_detect
      -> snd_jack_set_key
 rk_init
   -> snd_soc_card_jack_new

This patch moves the new jack object creation from rk_init
to rk_98090_headset_init function making sure the jack is
created before is accessed.

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/rockchip/rockchip_max98090.c | 50 ++++++++++++++++++----------------
 1 file changed, 27 insertions(+), 23 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index 543610282cdb..abb64a553967 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -114,43 +114,27 @@ static int rk_aif1_hw_params(struct snd_pcm_substream *substream,
 	return ret;
 }
 
-static int rk_init(struct snd_soc_pcm_runtime *runtime)
-{
-	/* Enable Headset and 4 Buttons Jack detection */
-	return snd_soc_card_jack_new(runtime->card, "Headset Jack",
-			       SND_JACK_HEADSET |
-			       SND_JACK_BTN_0 | SND_JACK_BTN_1 |
-			       SND_JACK_BTN_2 | SND_JACK_BTN_3,
-			       &headset_jack,
-			       headset_jack_pins,
-			       ARRAY_SIZE(headset_jack_pins));
-}
-
-static int rk_98090_headset_init(struct snd_soc_component *component)
-{
-	return ts3a227e_enable_jack_detect(component, &headset_jack);
-}
-
 static struct snd_soc_ops rk_aif1_ops = {
 	.hw_params = rk_aif1_hw_params,
 };
 
-static struct snd_soc_aux_dev rk_98090_headset_dev = {
-	.name = "Headset Chip",
-	.init = rk_98090_headset_init,
-};
-
 static struct snd_soc_dai_link rk_dailink = {
 	.name = "max98090",
 	.stream_name = "Audio",
 	.codec_dai_name = "HiFi",
-	.init = rk_init,
 	.ops = &rk_aif1_ops,
 	/* set max98090 as slave */
 	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
 		SND_SOC_DAIFMT_CBS_CFS,
 };
 
+static int rk_98090_headset_init(struct snd_soc_component *component);
+
+static struct snd_soc_aux_dev rk_98090_headset_dev = {
+	.name = "Headset Chip",
+	.init = rk_98090_headset_init,
+};
+
 static struct snd_soc_card snd_soc_card_rk = {
 	.name = "ROCKCHIP-I2S",
 	.owner = THIS_MODULE,
@@ -166,6 +150,26 @@ static struct snd_soc_card snd_soc_card_rk = {
 	.num_controls = ARRAY_SIZE(rk_mc_controls),
 };
 
+static int rk_98090_headset_init(struct snd_soc_component *component)
+{
+	int ret;
+
+	/* Enable Headset and 4 Buttons Jack detection */
+	ret = snd_soc_card_jack_new(&snd_soc_card_rk, "Headset Jack",
+				    SND_JACK_HEADSET |
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
+				    &headset_jack,
+				    headset_jack_pins,
+				    ARRAY_SIZE(headset_jack_pins));
+	if (ret)
+		return ret;
+
+	ret = ts3a227e_enable_jack_detect(component, &headset_jack);
+
+	return ret;
+}
+
 static int snd_rk_mc_probe(struct platform_device *pdev)
 {
 	int ret = 0;
-- 
2.8.1



From broonie at kernel.org  Tue May 10 11:49:59 2016
From: broonie at kernel.org (Mark Brown)
Date: Tue, 10 May 2016 19:49:59 +0100
Subject: Applied "ASoC: rockchip-max98090: Fix the Headset Mic route." to the
 asoc tree
In-Reply-To: <1462435421-21205-5-git-send-email-enric.balletbo@collabora.com>
Message-ID: <E1b0CjH-0008Tj-FE@debutante>

The patch

   ASoC: rockchip-max98090: Fix the Headset Mic route.

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 570204232a9578e5d098e7ad0c0cde0b59d30089 Mon Sep 17 00:00:00 2001
From: Enric Balletbo i Serra <enric.balletbo at collabora.com>
Date: Mon, 9 May 2016 12:46:32 +0200
Subject: [PATCH] ASoC: rockchip-max98090: Fix the Headset Mic route.

The path Headset Mic --> MICBIAS is wrong because connects a non-supply
widget as a source with a supply widget as a sink. It's the other way
around:

  MICBIAS (source) --> Headset Mic (sink).

This patch also shut up the following error message:

 rockchip-snd-max98090 sound: Connecting non-supply widget to supply widget is not supported (Headset Mic -> MICBIAS)
 rockchip-snd-max98090 sound: ASoC: no dapm match for Headset Mic --> (null) --> MICBIAS
 rockchip-snd-max98090 sound: ASoC: Failed to add route Headset Mic -> direct -> MICBIAS

Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/rockchip/rockchip_max98090.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/sound/soc/rockchip/rockchip_max98090.c b/sound/soc/rockchip/rockchip_max98090.c
index abb64a553967..3da7891b7dfb 100644
--- a/sound/soc/rockchip/rockchip_max98090.c
+++ b/sound/soc/rockchip/rockchip_max98090.c
@@ -53,7 +53,7 @@ static const struct snd_soc_dapm_widget rk_dapm_widgets[] = {
 static const struct snd_soc_dapm_route rk_audio_map[] = {
 	{"IN34", NULL, "Headset Mic"},
 	{"IN34", NULL, "MICBIAS"},
-	{"MICBIAS", NULL, "Headset Mic"},
+	{"Headset Mic", NULL, "MICBIAS"},
 	{"DMICL", NULL, "Int Mic"},
 	{"Headphone", NULL, "HPL"},
 	{"Headphone", NULL, "HPR"},
-- 
2.8.1



From arnd at arndb.de  Tue May 10 13:14:19 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 10 May 2016 22:14:19 +0200
Subject: [GIT PULL 3/3] Rockchip dts64 updates for v4.7 - part2
In-Reply-To: <14339181.jSmLu3hG44@diego>
References: <5544434.9tA8JHBIkp@diego> <14339181.jSmLu3hG44@diego>
Message-ID: <4588554.abhnjsmNOD@wuerfel>

On Friday 29 April 2016 00:25:22 Heiko St?bner wrote:
> Adding the new rk3399 core devicetree support as well as a board
> dts for the evaluation board of this chip and similar to the arm32
> side also move the rk3368 thermal data into the core soc dtsi, as
> there really is no need to keep it separate.
> 
> 
Pulled into next/dt64, thanks!

	Arnd


From dianders at chromium.org  Tue May 10 14:07:34 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 10 May 2016 14:07:34 -0700
Subject: [PATCH] pinctrl: rockchip: fix pull setting error for rk3399
In-Reply-To: <1462878896-28956-1-git-send-email-wxt@rock-chips.com>
References: <1462878896-28956-1-git-send-email-wxt@rock-chips.com>
Message-ID: <CAD=FV=VrE=9=sgqUXBMwmoQin8S+yPbAgnrO1VUgx5QafYWXhA@mail.gmail.com>

Caesar / David,

On Tue, May 10, 2016 at 4:14 AM, Caesar Wang <wxt at rock-chips.com> wrote:
> From: David Wu <david.wu at rock-chips.com>
>
> This patch fixes the pinctrl pull bias setting, since the pull up/down
> setting is the contrary for gpio0.

Commit message only mentions gpio0, but gpio2 is also fixed in the
commit.  Please mention gpio2 in the commit message.


> From the TRM said, the gpio0 pull polarity setting:
> gpio0a_p (gpio0 )
> GPIO0A PE/PS programmation section, every
> GPIO bit corresponding to 2bits[PS:PE]
> 2'b00: Z(Noraml operaton);
> 2'b11: weak 1(pull-up);
> 2'b01: weak 0(pull-down);
> 2'b10: Z(Noraml operaton);

Despite the fact that the typo (Noralm vs. Normal) is present in the
TRM, maybe we should fix it here?


> Then, the other gpios setting as the following:
> gpio1a_p (gpio1, gpio2, gpio3...)
> GPIO1A PU/PD programmation section, every
> GPIO bit corresponding to 2bits
> 2'b00: Z(Noraml operaton);
> 2'b01: weak 1(pull-up);
> 2'b10: weak 0(pull-down);
> 2'b11: Repeater(Bus keeper)
>
> For example,(rk3399evb board)
> sdmmc_cd --->gpio0_a7
> localhost / # io -r -4 0xff320040
> ff320040: 00004d5f
> In general,the value should be 0x0000cd5f since the pin set in the dts.
>
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Linus Walleij <linus.walleij at linaro.org>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Cc: linux-gpio at vger.kernel.org
> ---
>
>  drivers/pinctrl/pinctrl-rockchip.c | 178 ++++++++++++++++++++++++++-----------
>  1 file changed, 126 insertions(+), 52 deletions(-)
>
> diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
> index 596b869..38be9c7 100644
> --- a/drivers/pinctrl/pinctrl-rockchip.c
> +++ b/drivers/pinctrl/pinctrl-rockchip.c
> @@ -99,6 +99,15 @@ enum rockchip_pin_drv_type {
>  };
>
>  /**
> + * enum type index corresponding to rockchip_pull_list arrays index.
> + */
> +enum rockchip_pin_pull_type {
> +       PULL_TYPE_IO_DEFAULT = 0,
> +       PULL_TYPE_IO_1V8_ONLY,
> +       PULL_TYPE_MAX
> +};
> +
> +/**
>   * @drv_type: drive strength variant using rockchip_perpin_drv_type
>   * @offset: if initialized to -1 it will be autocalculated, by specifying
>   *         an initial offset value the relevant source offset can be reset
> @@ -123,6 +132,7 @@ struct rockchip_drv {
>   * @bank_num: number of the bank, to account for holes
>   * @iomux: array describing the 4 iomux sources of the bank
>   * @drv: array describing the 4 drive strength sources of the bank
> + * @pull_type: array describing the 4 pull type sources of the bank
>   * @valid: are all necessary informations present
>   * @of_node: dt node of this bank
>   * @drvdata: common pinctrl basedata
> @@ -143,6 +153,7 @@ struct rockchip_pin_bank {
>         u8                              bank_num;
>         struct rockchip_iomux           iomux[4];
>         struct rockchip_drv             drv[4];
> +       enum rockchip_pin_pull_type     pull_type[4];
>         bool                            valid;
>         struct device_node              *of_node;
>         struct rockchip_pinctrl         *drvdata;
> @@ -198,6 +209,31 @@ struct rockchip_pin_bank {
>                 },                                                      \
>         }
>
> +#define PIN_BANK_DRV_FLAGS_PULL_FLAGS(id, pins, label, drv0, drv1,     \
> +                                     drv2, drv3, pull0, pull1,         \
> +                                     pull2, pull3)                     \
> +       {                                                               \
> +               .bank_num       = id,                                   \
> +               .nr_pins        = pins,                                 \
> +               .name           = label,                                \
> +               .iomux          = {                                     \
> +                       { .offset = -1 },                               \
> +                       { .offset = -1 },                               \
> +                       { .offset = -1 },                               \
> +                       { .offset = -1 },                               \
> +               },                                                      \
> +               .drv            = {                                     \
> +                       { .drv_type = drv0, .offset = -1 },             \
> +                       { .drv_type = drv1, .offset = -1 },             \
> +                       { .drv_type = drv2, .offset = -1 },             \
> +                       { .drv_type = drv3, .offset = -1 },             \
> +               },                                                      \
> +               .pull_type[0] = pull0,                                  \
> +               .pull_type[1] = pull1,                                  \
> +               .pull_type[2] = pull2,                                  \
> +               .pull_type[3] = pull3,                                  \
> +       }
> +
>  #define PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(id, pins, label, iom0, iom1,   \
>                                         iom2, iom3, drv0, drv1, drv2,   \
>                                         drv3, offset0, offset1,         \
> @@ -220,6 +256,34 @@ struct rockchip_pin_bank {
>                 },                                                      \
>         }
>
> +#define PIN_BANK_IOMUX_FLAGS_DRV_FLAGS_OFFSET_PULL_FLAGS(id, pins,     \
> +                                             label, iom0, iom1, iom2,  \
> +                                             iom3, drv0, drv1, drv2,   \
> +                                             drv3, offset0, offset1,   \
> +                                             offset2, offset3, pull0,  \
> +                                             pull1, pull2, pull3)      \
> +       {                                                               \
> +               .bank_num       = id,                                   \
> +               .nr_pins        = pins,                                 \
> +               .name           = label,                                \
> +               .iomux          = {                                     \
> +                       { .type = iom0, .offset = -1 },                 \
> +                       { .type = iom1, .offset = -1 },                 \
> +                       { .type = iom2, .offset = -1 },                 \
> +                       { .type = iom3, .offset = -1 },                 \
> +               },                                                      \
> +               .drv            = {                                     \
> +                       { .drv_type = drv0, .offset = offset0 },        \
> +                       { .drv_type = drv1, .offset = offset1 },        \
> +                       { .drv_type = drv2, .offset = offset2 },        \
> +                       { .drv_type = drv3, .offset = offset3 },        \
> +               },                                                      \
> +               .pull_type[0] = pull0,                                  \
> +               .pull_type[1] = pull1,                                  \
> +               .pull_type[2] = pull2,                                  \
> +               .pull_type[3] = pull3,                                  \
> +       }
> +
>  /**
>   */
>  struct rockchip_pin_ctrl {
> @@ -1020,12 +1084,27 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
>         return ret;
>  }
>
> +static int rockchip_pull_list[PULL_TYPE_MAX][4] = {
> +       {
> +               PIN_CONFIG_BIAS_DISABLE,
> +               PIN_CONFIG_BIAS_PULL_UP,
> +               PIN_CONFIG_BIAS_PULL_DOWN,
> +               PIN_CONFIG_BIAS_BUS_HOLD
> +       },
> +       {
> +               PIN_CONFIG_BIAS_DISABLE,
> +               PIN_CONFIG_BIAS_PULL_DOWN,
> +               PIN_CONFIG_BIAS_DISABLE,
> +               PIN_CONFIG_BIAS_PULL_UP
> +       },
> +};
> +
>  static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
>  {
>         struct rockchip_pinctrl *info = bank->drvdata;
>         struct rockchip_pin_ctrl *ctrl = info->ctrl;
>         struct regmap *regmap;
> -       int reg, ret;
> +       int reg, ret, pull_type;
>         u8 bit;
>         u32 data;
>
> @@ -1048,22 +1127,11 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
>         case RK3288:
>         case RK3368:
>         case RK3399:
> +               pull_type = bank->pull_type[pin_num / 8];
>                 data >>= bit;
>                 data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1;
>
> -               switch (data) {
> -               case 0:
> -                       return PIN_CONFIG_BIAS_DISABLE;
> -               case 1:
> -                       return PIN_CONFIG_BIAS_PULL_UP;
> -               case 2:
> -                       return PIN_CONFIG_BIAS_PULL_DOWN;
> -               case 3:
> -                       return PIN_CONFIG_BIAS_BUS_HOLD;
> -               }
> -
> -               dev_err(info->dev, "unknown pull setting\n");
> -               return -EIO;
> +               return rockchip_pull_list[pull_type][data];
>         default:
>                 dev_err(info->dev, "unsupported pinctrl type\n");
>                 return -EINVAL;
> @@ -1076,7 +1144,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
>         struct rockchip_pinctrl *info = bank->drvdata;
>         struct rockchip_pin_ctrl *ctrl = info->ctrl;
>         struct regmap *regmap;
> -       int reg, ret;
> +       int reg, ret, i, pull_type;
>         unsigned long flags;
>         u8 bit;
>         u32 data, rmask;
> @@ -1105,30 +1173,27 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
>         case RK3288:
>         case RK3368:
>         case RK3399:
> +               pull_type = bank->pull_type[pin_num / 8];
> +               ret = -EINVAL;
> +               for (i = 0; i < ARRAY_SIZE(rockchip_pull_list[pull_type]);
> +                       i++) {
> +                       if (rockchip_pull_list[pull_type][i] == pull) {
> +                               ret = i;
> +                               break;
> +                       }
> +               }
> +
> +               if (ret < 0) {
> +                       dev_err(info->dev, "unknown pull setting %d\n", pull);

nit: why change the error message?  Old message was "unsupported"
instead of your new "unknown".  "unsupported" was better IMHO.



> +                       return ret;
> +               }
> +
>                 spin_lock_irqsave(&bank->slock, flags);
>
>                 /* enable the write to the equivalent lower bits */
>                 data = ((1 << RK3188_PULL_BITS_PER_PIN) - 1) << (bit + 16);
>                 rmask = data | (data >> 16);
> -
> -               switch (pull) {
> -               case PIN_CONFIG_BIAS_DISABLE:
> -                       break;
> -               case PIN_CONFIG_BIAS_PULL_UP:
> -                       data |= (1 << bit);
> -                       break;
> -               case PIN_CONFIG_BIAS_PULL_DOWN:
> -                       data |= (2 << bit);
> -                       break;
> -               case PIN_CONFIG_BIAS_BUS_HOLD:
> -                       data |= (3 << bit);
> -                       break;
> -               default:
> -                       spin_unlock_irqrestore(&bank->slock, flags);
> -                       dev_err(info->dev, "unsupported pull setting %d\n",
> -                               pull);
> -                       return -EINVAL;
> -               }
> +               data |= (ret << bit);
>
>                 ret = regmap_update_bits(regmap, reg, rmask, data);
>
> @@ -2552,19 +2617,24 @@ static struct rockchip_pin_ctrl rk3368_pin_ctrl = {
>  };
>
>  static struct rockchip_pin_bank rk3399_pin_banks[] = {
> -       PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(0, 32, "gpio0", IOMUX_SOURCE_PMU,
> -                                       IOMUX_SOURCE_PMU,
> -                                       IOMUX_SOURCE_PMU,
> -                                       IOMUX_SOURCE_PMU,
> -                                       DRV_TYPE_IO_1V8_ONLY,
> -                                       DRV_TYPE_IO_1V8_ONLY,
> -                                       DRV_TYPE_IO_DEFAULT,
> -                                       DRV_TYPE_IO_DEFAULT,
> -                                       0x0,
> -                                       0x8,
> -                                       -1,
> -                                       -1
> -                                       ),
> +       PIN_BANK_IOMUX_FLAGS_DRV_FLAGS_OFFSET_PULL_FLAGS(0, 32, "gpio0",
> +                                                        IOMUX_SOURCE_PMU,
> +                                                        IOMUX_SOURCE_PMU,
> +                                                        IOMUX_SOURCE_PMU,
> +                                                        IOMUX_SOURCE_PMU,
> +                                                        DRV_TYPE_IO_1V8_ONLY,
> +                                                        DRV_TYPE_IO_1V8_ONLY,
> +                                                        DRV_TYPE_IO_DEFAULT,
> +                                                        DRV_TYPE_IO_DEFAULT,
> +                                                        0x0,
> +                                                        0x8,
> +                                                        -1,
> +                                                        -1,
> +                                                        PULL_TYPE_IO_1V8_ONLY,
> +                                                        PULL_TYPE_IO_1V8_ONLY,
> +                                                        PULL_TYPE_IO_DEFAULT,
> +                                                        PULL_TYPE_IO_DEFAULT
> +                                                       ),
>         PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(1, 32, "gpio1", IOMUX_SOURCE_PMU,
>                                         IOMUX_SOURCE_PMU,
>                                         IOMUX_SOURCE_PMU,
> @@ -2578,11 +2648,15 @@ static struct rockchip_pin_bank rk3399_pin_banks[] = {
>                                         0x30,
>                                         0x38
>                                         ),
> -       PIN_BANK_DRV_FLAGS(2, 32, "gpio2", DRV_TYPE_IO_1V8_OR_3V0,
> -                          DRV_TYPE_IO_1V8_OR_3V0,
> -                          DRV_TYPE_IO_1V8_ONLY,
> -                          DRV_TYPE_IO_1V8_ONLY
> -                          ),
> +       PIN_BANK_DRV_FLAGS_PULL_FLAGS(2, 32, "gpio2", DRV_TYPE_IO_1V8_OR_3V0,
> +                                     DRV_TYPE_IO_1V8_OR_3V0,
> +                                     DRV_TYPE_IO_1V8_ONLY,
> +                                     DRV_TYPE_IO_1V8_ONLY,
> +                                     PULL_TYPE_IO_DEFAULT,
> +                                     PULL_TYPE_IO_DEFAULT,
> +                                     PULL_TYPE_IO_1V8_ONLY,
> +                                     PULL_TYPE_IO_1V8_ONLY

Are you certain that gpio2 behaves the same way?  The TRM I have says
this for GPIO2C and GPIO2D:

2'b00: pervious-state
2'b01: weak 0(pull-down);
2'b10: pervious-state
2'b11: weak 1(pull-up);

Assuming that "pervious-state" is a simple typo for "previous state"
that would imply that it was behaving as "bus hold" and _not_ "bias
disable".

Note: if it actually is a "bus hold" state then we'll have to figure
out how this would work with existing device trees.  I'd imagine that
they are currently specifying "bias disable" and technically that
might not be possible?



-Doug


From briannorris at chromium.org  Tue May 10 17:02:54 2016
From: briannorris at chromium.org (Brian Norris)
Date: Tue, 10 May 2016 17:02:54 -0700
Subject: [PATCH 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
Message-ID: <1462924975-69072-1-git-send-email-briannorris@chromium.org>

The bindings for rk3399's SDHCI + eMMC PHY have been accepted, so let's
support eMMC now.

Note that 'rockchip,rk3399-sdhci-5.1' is not documented, but per Heiko's
previous suggestion, we don't want to clutter the arasan doc, and it's
just a precautionary measure to have it.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 23 ++++++++++++++++++++++-
 1 file changed, 22 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a143b0..947d1221592d 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -215,6 +215,17 @@
 		status = "disabled";
 	};
 
+	sdhci: sdhci at fe330000 {
+		compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
+		reg = <0x0 0xfe330000 0x0 0x10000>;
+		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
+		clock-names = "clk_xin", "clk_ahb";
+		phys = <&emmc_phy>;
+		phy-names = "phy_arasan";
+		status = "disabled";
+	};
+
 	usb_host0_ehci: usb at fe380000 {
 		compatible = "generic-ehci";
 		reg = <0x0 0xfe380000 0x0 0x20000>;
@@ -481,8 +492,18 @@
 	};
 
 	grf: syscon at ff770000 {
-		compatible = "rockchip,rk3399-grf", "syscon";
+		compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
 		reg = <0x0 0xff770000 0x0 0x10000>;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		emmc_phy: phy at f780 {
+			compatible = "rockchip,rk3399-emmc-phy";
+			reg = <0xf780 0x20>;
+			#phy-cells = <0>;
+			status = "disabled";
+		};
 	};
 
 	watchdog at ff840000 {
-- 
2.8.0.rc3.226.g39d4020



From briannorris at chromium.org  Tue May 10 17:02:55 2016
From: briannorris at chromium.org (Brian Norris)
Date: Tue, 10 May 2016 17:02:55 -0700
Subject: [PATCH 2/2] ARM64: dts: rockchip: enable eMMC for rk3399 EVB
In-Reply-To: <1462924975-69072-1-git-send-email-briannorris@chromium.org>
References: <1462924975-69072-1-git-send-email-briannorris@chromium.org>
Message-ID: <1462924975-69072-2-git-send-email-briannorris@chromium.org>

The 'mmc-hs400-enhanced-strobe' property has been acked by Rob Herring,
though it's still not merged.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
index 1a3eb1482050..ccfd2bcf02e1 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
@@ -89,6 +89,18 @@
 	status = "okay";
 };
 
+&emmc_phy {
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	mmc-hs400-1_8v;
+	non-removable;
+	mmc-hs400-enhanced-strobe;
+	status = "okay";
+};
+
 &uart2 {
 	status = "okay";
 };
-- 
2.8.0.rc3.226.g39d4020



From shawn.lin at rock-chips.com  Tue May 10 17:59:24 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Wed, 11 May 2016 08:59:24 +0800
Subject: [PATCH 2/2] ARM64: dts: rockchip: enable eMMC for rk3399 EVB
In-Reply-To: <1462924975-69072-2-git-send-email-briannorris@chromium.org>
References: <1462924975-69072-1-git-send-email-briannorris@chromium.org>
 <1462924975-69072-2-git-send-email-briannorris@chromium.org>
Message-ID: <d8dc5609-3cf6-80ce-462b-d46f0ea6dcff@rock-chips.com>

On 2016/5/11 8:02, Brian Norris wrote:
> The 'mmc-hs400-enhanced-strobe' property has been acked by Rob Herring,
> though it's still not merged.
>

Hi Brain,

I'm not sure whether it's acceptable to upstream new property which
isn't merged yet. My major concern is that as the patchset supporting
h400es will go through mmc tree, so if Ulf should want to shorten the
name (e.g mmc-hs400-es), you would respin this patch.


Thanks.

> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
>  arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> index 1a3eb1482050..ccfd2bcf02e1 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> @@ -89,6 +89,18 @@
>  	status = "okay";
>  };
>
> +&emmc_phy {
> +	status = "okay";
> +};
> +
> +&sdhci {
> +	bus-width = <8>;
> +	mmc-hs400-1_8v;
> +	non-removable;
> +	mmc-hs400-enhanced-strobe;
> +	status = "okay";
> +};
> +
>  &uart2 {
>  	status = "okay";
>  };
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Tue May 10 18:17:38 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Wed, 11 May 2016 09:17:38 +0800
Subject: [PATCH 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
In-Reply-To: <1462924975-69072-1-git-send-email-briannorris@chromium.org>
References: <1462924975-69072-1-git-send-email-briannorris@chromium.org>
Message-ID: <3e257ce2-056a-592a-9481-970da1fe0627@rock-chips.com>

+ Huang Lin

On 2016/5/11 8:02, Brian Norris wrote:
> The bindings for rk3399's SDHCI + eMMC PHY have been accepted, so let's
> support eMMC now.
>
> Note that 'rockchip,rk3399-sdhci-5.1' is not documented, but per Heiko's
> previous suggestion, we don't want to clutter the arasan doc, and it's
> just a precautionary measure to have it.
>
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi | 23 ++++++++++++++++++++++-
>  1 file changed, 22 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> index 46f325a143b0..947d1221592d 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -215,6 +215,17 @@
>  		status = "disabled";
>  	};
>
> +	sdhci: sdhci at fe330000 {
> +		compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
> +		reg = <0x0 0xfe330000 0x0 0x10000>;
> +		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;

sdhci doesn't call clk_set_rate to explicitly assign clk_xin to 200MHz
as it always assumes sdhci controller should meet the highest speed of
each timing mode. And the internal divider will be used. So IMHO,
clk-rockchip for 3399 *haven't* made clk_xin to be 200MHz. Let's assign
the clk stuff to make sure it's 200MHz.

Another problem is that emmc_phy contains a configuration which should
be consistent with clk_out(namely clk_xin/internal dividor). Now I don't
submit unpstream patchset to expose these configurarion, but in
prevention of some misleading, I think it's better to to it.

How about adding these?

assigned-clocks = <&cru SCLK_EMMC>;
assigned-clock-parents = <&cru PLL_CPLL>; //may not need
assigned-clock-rates = <200000000>;

Still you limit your clk_out by adding max-frequency in dts for
specific requirment.

We here manually assigne the clk_xin to be 200MHz, so defaultly
when it's runing in HS200/HS400(ES) mode, internal divider won't
be used(by-pass mode). So the clk jitter is better when by-passing the
clock.

Thanks.

> +		clock-names = "clk_xin", "clk_ahb";
> +		phys = <&emmc_phy>;
> +		phy-names = "phy_arasan";
> +		status = "disabled";
> +	};
> +
>  	usb_host0_ehci: usb at fe380000 {
>  		compatible = "generic-ehci";
>  		reg = <0x0 0xfe380000 0x0 0x20000>;
> @@ -481,8 +492,18 @@
>  	};
>
>  	grf: syscon at ff770000 {
> -		compatible = "rockchip,rk3399-grf", "syscon";
> +		compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
>  		reg = <0x0 0xff770000 0x0 0x10000>;
> +
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +
> +		emmc_phy: phy at f780 {
> +			compatible = "rockchip,rk3399-emmc-phy";
> +			reg = <0xf780 0x20>;
> +			#phy-cells = <0>;
> +			status = "disabled";
> +		};
>  	};
>
>  	watchdog at ff840000 {
>


-- 
Best Regards
Shawn Lin



From briannorris at chromium.org  Tue May 10 18:19:19 2016
From: briannorris at chromium.org (Brian Norris)
Date: Tue, 10 May 2016 18:19:19 -0700
Subject: [PATCH 2/2] ARM64: dts: rockchip: enable eMMC for rk3399 EVB
In-Reply-To: <d8dc5609-3cf6-80ce-462b-d46f0ea6dcff@rock-chips.com>
References: <1462924975-69072-1-git-send-email-briannorris@chromium.org>
 <1462924975-69072-2-git-send-email-briannorris@chromium.org>
 <d8dc5609-3cf6-80ce-462b-d46f0ea6dcff@rock-chips.com>
Message-ID: <20160511011919.GB77327@google.com>

Hi,

On Wed, May 11, 2016 at 08:59:24AM +0800, Shawn Lin wrote:
> On 2016/5/11 8:02, Brian Norris wrote:
> >The 'mmc-hs400-enhanced-strobe' property has been acked by Rob Herring,
> >though it's still not merged.
> >
> 
> Hi Brain,
> 
> I'm not sure whether it's acceptable to upstream new property which
> isn't merged yet. My major concern is that as the patchset supporting
> h400es will go through mmc tree, so if Ulf should want to shorten the
> name (e.g mmc-hs400-es), you would respin this patch.


Well, Heiko can determine when to accept this. I wanted to post it to
get things moving, but I can drop that property for now if it's going to
cause difficulty.

> Thanks.
> 
> >Signed-off-by: Brian Norris <briannorris at chromium.org>
> >---

BTW, I meant to note here that I haven't personally tested this EVB. I
have tested other boards. This patch mostly serves the purpose of an
example user, for my purposes.

Brian

> > arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 12 ++++++++++++
> > 1 file changed, 12 insertions(+)
> >
> >diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> >index 1a3eb1482050..ccfd2bcf02e1 100644
> >--- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> >+++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> >@@ -89,6 +89,18 @@
> > 	status = "okay";
> > };
> >
> >+&emmc_phy {
> >+	status = "okay";
> >+};
> >+
> >+&sdhci {
> >+	bus-width = <8>;
> >+	mmc-hs400-1_8v;
> >+	non-removable;
> >+	mmc-hs400-enhanced-strobe;
> >+	status = "okay";
> >+};
> >+
> > &uart2 {
> > 	status = "okay";
> > };
> >
> 
> 
> -- 
> Best Regards
> Shawn Lin
> 


From shawn.lin at rock-chips.com  Tue May 10 19:50:17 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Wed, 11 May 2016 10:50:17 +0800
Subject: [PATCH 2/2] dt-bindings: rockchip-dw-mshc: add
 rockchip,default-drv-phase
In-Reply-To: <CAD=FV=UGbrJRyUbbgzbcYf9GjPG+Fh_gpQ3rX2G=wi2w5Lw=Sg@mail.gmail.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
 <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=WSkBwBjVsRoDsfjD+sNfR70mKGRA0khjPKKW0zS2=PTw@mail.gmail.com>
 <b15dcb4f-1584-8219-2fe0-97eecb0c64a6@rock-chips.com>
 <CAD=FV=XToSzqSh=SShHuQU9W_m7gfyQn8wRXkLy79t+tnqZknA@mail.gmail.com>
 <1f2f43c7-2672-e448-eddb-2d613bb8dc48@rock-chips.com>
 <CAD=FV=UGbrJRyUbbgzbcYf9GjPG+Fh_gpQ3rX2G=wi2w5Lw=Sg@mail.gmail.com>
Message-ID: <e202f663-88d7-693b-a765-c130e68d1c2d@rock-chips.com>

On 2016/5/10 23:57, Doug Anderson wrote:
> (again, but not HTML)
>

------8<------------------

>
> I have less faith than you in the TRM.  The TRM is full of minor
> errors and is often wrong about the default state of things.  IMHO the
> only true way to find out is to boot up some SoCs and check.
>

Okay, I should not have too much confidence on my TRM maybe :).

Again, We SHOULD refer to the Mobile Storage Host section (Variable
Delay/Clock Generation) instead of CRU section, otherwise even you will
see inconsistent decription of mmc_clock->shift.



> As far as whether code touches these values:
>

---------8<-----------------

>>
>> maybe. But I think 180(downside) is the better.

NAK my previous comments here. Downside is better for SRD, but won't
work for DDR mode. When running in DDR mode, we should use 90 instead.

So let me elaborate a bit more here.
For DDR mode, one single clk cycle should sending two data bits outside
to the devices. We need a hold time for both. If 180 is used, the first
bit occurs around the downside area, which won't be sampled by devices
on the upside.  So on the upside, the devices will see a zero bit if you
actually send a one-bit, which makes the devices  generate CRC finally.


For this above, 180 for all SDR mode is ok, but 90 should be deployed
for DDR mode. So simply checking the timing to hardcode it should be
fine.

>
> I'm OK with using 180 always as long as SD cards continue to work OK.
> Best would be if someone could actually run a protocol analyzer for
> all the different speed modes.
>
>
>>> Also: I still haven't heard whether there is any downside to using 180
>>> degrees for modes that only require 90 degrees.  Does it cause
>>> problems to just always use 180 degrees?  If not, we could possibly
>>> use 180 degrees everywhere and just hardcode it?
>>
>>



-- 
Best Regards
Shawn Lin



From wxt at rock-chips.com  Tue May 10 20:31:25 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 11 May 2016 11:31:25 +0800
Subject: [PATCH] pinctrl: rockchip: fix pull setting error for rk3399
In-Reply-To: <CAD=FV=VrE=9=sgqUXBMwmoQin8S+yPbAgnrO1VUgx5QafYWXhA@mail.gmail.com>
References: <1462878896-28956-1-git-send-email-wxt@rock-chips.com>
 <CAD=FV=VrE=9=sgqUXBMwmoQin8S+yPbAgnrO1VUgx5QafYWXhA@mail.gmail.com>
Message-ID: <5732A78D.7040308@rock-chips.com>

Doug,

? 2016?05?11? 05:07, Doug Anderson ??:
> Caesar / David,
>
> On Tue, May 10, 2016 at 4:14 AM, Caesar Wang <wxt at rock-chips.com> wrote:
>> From: David Wu <david.wu at rock-chips.com>
>>
>> This patch fixes the pinctrl pull bias setting, since the pull up/down
>> setting is the contrary for gpio0.
> Commit message only mentions gpio0, but gpio2 is also fixed in the
> commit.  Please mention gpio2 in the commit message.

Fix it in next version.

>
>>  From the TRM said, the gpio0 pull polarity setting:
>> gpio0a_p (gpio0 )
>> GPIO0A PE/PS programmation section, every
>> GPIO bit corresponding to 2bits[PS:PE]
>> 2'b00: Z(Noraml operaton);
>> 2'b11: weak 1(pull-up);
>> 2'b01: weak 0(pull-down);
>> 2'b10: Z(Noraml operaton);
> Despite the fact that the typo (Noralm vs. Normal) is present in the
> TRM, maybe we should fix it here?

Yep, ditto.

> <cut>
>
> +
> +               if (ret < 0) {
> +                       dev_err(info->dev, "unknown pull setting %d\n", pull);
> nit: why change the error message?  Old message was "unsupported"
> instead of your new "unknown".  "unsupported" was better IMHO.

Okay, sound resonable.

>
>
>> -       PIN_BANK_DRV_FLAGS(2, 32, "gpio2", DRV_TYPE_IO_1V8_OR_3V0,
>> -                          DRV_TYPE_IO_1V8_OR_3V0,
>> -                          DRV_TYPE_IO_1V8_ONLY,
>> -                          DRV_TYPE_IO_1V8_ONLY
>> -                          ),
>> +       PIN_BANK_DRV_FLAGS_PULL_FLAGS(2, 32, "gpio2", DRV_TYPE_IO_1V8_OR_3V0,
>> +                                     DRV_TYPE_IO_1V8_OR_3V0,
>> +                                     DRV_TYPE_IO_1V8_ONLY,
>> +                                     DRV_TYPE_IO_1V8_ONLY,
>> +                                     PULL_TYPE_IO_DEFAULT,
>> +                                     PULL_TYPE_IO_DEFAULT,
>>
> Are you certain that gpio2 behaves the same way?  The TRM I have says
> this for GPIO2C and GPIO2D:

+                                     PULL_TYPE_IO_1V8_ONLY,
+                                     PULL_TYPE_IO_1V8_ONLY

Yep, so this just set the gpio2c&gpio2d in this function.

>
> 2'b00: pervious-state
> 2'b01: weak 0(pull-down);
> 2'b10: pervious-state
> 2'b11: weak 1(pull-up);
>
> Assuming that "pervious-state" is a simple typo for "previous state"
> that would imply that it was behaving as "bus hold" and _not_ "bias
> disable".

I will say that TRM made the mistake since this is *not* exist.
Okay, fixes by the newer TRM.

>
> Note: if it actually is a "bus hold" state then we'll have to figure
> out how this would work with existing device trees.  I'd imagine that
> they are currently specifying "bias disable" and technically that
> might not be possible?
>
>
>
> -Doug
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>


From wxt at rock-chips.com  Tue May 10 20:39:28 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 11 May 2016 11:39:28 +0800
Subject: [PATCH v2] pinctrl: rockchip: fix pull setting error for rk3399
Message-ID: <1462937968-4952-1-git-send-email-wxt@rock-chips.com>

From: David Wu <david.wu at rock-chips.com>

This patch fixes the pinctrl pull bias setting, since the pull up/down
setting is the contrary for gpio0(just the gpio0a and gpio0b) and
gpio2(just the gpio2c and gpio2d).

>From the TRM said, the gpio0a pull polarity setting:
gpio0a_p
GPIO0A PE/PS programmation section, every
GPIO bit corresponding to 2bits[PS:PE]
2'b00: Z(Normal operation);
2'b11: weak 1(pull-up);
2'b01: weak 0(pull-down);
2'b10: Z(Normal operation);

Then, the other gpios setting as the following:
gpio1a_p (e.g.: gpio1, gpio2a, gpio2b, gpio3...)
GPIO1A PU/PD programmation section, every
GPIO bit corresponding to 2bits
2'b00: Z(Normal operation);
2'b01: weak 1(pull-up);
2'b10: weak 0(pull-down);
2'b11: Z(Normal operation);

For example,(rk3399evb board)
sdmmc_cd --->gpio0_a7
localhost / # io -r -4 0xff320040
ff320040: 00004d5f
In general,the value should be 0x0000cd5f since the pin has been set
in the dts.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Linus Walleij <linus.walleij at linaro.org>
Cc: Heiko Stuebner <heiko at sntech.de>
Cc: linux-gpio at vger.kernel.org
---

Changes in v2:
- As Doug commnets on https://patchwork.kernel.org/patch/9056961/
- update the commit for gpio2.
- change the print error messgae.

 drivers/pinctrl/pinctrl-rockchip.c | 179 ++++++++++++++++++++++++++-----------
 1 file changed, 127 insertions(+), 52 deletions(-)

diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 596b869..a91026e 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -99,6 +99,15 @@ enum rockchip_pin_drv_type {
 };
 
 /**
+ * enum type index corresponding to rockchip_pull_list arrays index.
+ */
+enum rockchip_pin_pull_type {
+	PULL_TYPE_IO_DEFAULT = 0,
+	PULL_TYPE_IO_1V8_ONLY,
+	PULL_TYPE_MAX
+};
+
+/**
  * @drv_type: drive strength variant using rockchip_perpin_drv_type
  * @offset: if initialized to -1 it will be autocalculated, by specifying
  *	    an initial offset value the relevant source offset can be reset
@@ -123,6 +132,7 @@ struct rockchip_drv {
  * @bank_num: number of the bank, to account for holes
  * @iomux: array describing the 4 iomux sources of the bank
  * @drv: array describing the 4 drive strength sources of the bank
+ * @pull_type: array describing the 4 pull type sources of the bank
  * @valid: are all necessary informations present
  * @of_node: dt node of this bank
  * @drvdata: common pinctrl basedata
@@ -143,6 +153,7 @@ struct rockchip_pin_bank {
 	u8				bank_num;
 	struct rockchip_iomux		iomux[4];
 	struct rockchip_drv		drv[4];
+	enum rockchip_pin_pull_type	pull_type[4];
 	bool				valid;
 	struct device_node		*of_node;
 	struct rockchip_pinctrl		*drvdata;
@@ -198,6 +209,31 @@ struct rockchip_pin_bank {
 		},							\
 	}
 
+#define PIN_BANK_DRV_FLAGS_PULL_FLAGS(id, pins, label, drv0, drv1,	\
+				      drv2, drv3, pull0, pull1,		\
+				      pull2, pull3)			\
+	{								\
+		.bank_num	= id,					\
+		.nr_pins	= pins,					\
+		.name		= label,				\
+		.iomux		= {					\
+			{ .offset = -1 },				\
+			{ .offset = -1 },				\
+			{ .offset = -1 },				\
+			{ .offset = -1 },				\
+		},							\
+		.drv		= {					\
+			{ .drv_type = drv0, .offset = -1 },		\
+			{ .drv_type = drv1, .offset = -1 },		\
+			{ .drv_type = drv2, .offset = -1 },		\
+			{ .drv_type = drv3, .offset = -1 },		\
+		},							\
+		.pull_type[0] = pull0,					\
+		.pull_type[1] = pull1,					\
+		.pull_type[2] = pull2,					\
+		.pull_type[3] = pull3,					\
+	}
+
 #define PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(id, pins, label, iom0, iom1,	\
 					iom2, iom3, drv0, drv1, drv2,	\
 					drv3, offset0, offset1,		\
@@ -220,6 +256,34 @@ struct rockchip_pin_bank {
 		},							\
 	}
 
+#define PIN_BANK_IOMUX_FLAGS_DRV_FLAGS_OFFSET_PULL_FLAGS(id, pins,	\
+					      label, iom0, iom1, iom2,  \
+					      iom3, drv0, drv1, drv2,   \
+					      drv3, offset0, offset1,   \
+					      offset2, offset3, pull0,  \
+					      pull1, pull2, pull3)	\
+	{								\
+		.bank_num	= id,					\
+		.nr_pins	= pins,					\
+		.name		= label,				\
+		.iomux		= {					\
+			{ .type = iom0, .offset = -1 },			\
+			{ .type = iom1, .offset = -1 },			\
+			{ .type = iom2, .offset = -1 },			\
+			{ .type = iom3, .offset = -1 },			\
+		},							\
+		.drv		= {					\
+			{ .drv_type = drv0, .offset = offset0 },	\
+			{ .drv_type = drv1, .offset = offset1 },	\
+			{ .drv_type = drv2, .offset = offset2 },	\
+			{ .drv_type = drv3, .offset = offset3 },	\
+		},							\
+		.pull_type[0] = pull0,					\
+		.pull_type[1] = pull1,					\
+		.pull_type[2] = pull2,					\
+		.pull_type[3] = pull3,					\
+	}
+
 /**
  */
 struct rockchip_pin_ctrl {
@@ -1020,12 +1084,27 @@ static int rockchip_set_drive_perpin(struct rockchip_pin_bank *bank,
 	return ret;
 }
 
+static int rockchip_pull_list[PULL_TYPE_MAX][4] = {
+	{
+		PIN_CONFIG_BIAS_DISABLE,
+		PIN_CONFIG_BIAS_PULL_UP,
+		PIN_CONFIG_BIAS_PULL_DOWN,
+		PIN_CONFIG_BIAS_BUS_HOLD
+	},
+	{
+		PIN_CONFIG_BIAS_DISABLE,
+		PIN_CONFIG_BIAS_PULL_DOWN,
+		PIN_CONFIG_BIAS_DISABLE,
+		PIN_CONFIG_BIAS_PULL_UP
+	},
+};
+
 static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
 {
 	struct rockchip_pinctrl *info = bank->drvdata;
 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
 	struct regmap *regmap;
-	int reg, ret;
+	int reg, ret, pull_type;
 	u8 bit;
 	u32 data;
 
@@ -1048,22 +1127,11 @@ static int rockchip_get_pull(struct rockchip_pin_bank *bank, int pin_num)
 	case RK3288:
 	case RK3368:
 	case RK3399:
+		pull_type = bank->pull_type[pin_num / 8];
 		data >>= bit;
 		data &= (1 << RK3188_PULL_BITS_PER_PIN) - 1;
 
-		switch (data) {
-		case 0:
-			return PIN_CONFIG_BIAS_DISABLE;
-		case 1:
-			return PIN_CONFIG_BIAS_PULL_UP;
-		case 2:
-			return PIN_CONFIG_BIAS_PULL_DOWN;
-		case 3:
-			return PIN_CONFIG_BIAS_BUS_HOLD;
-		}
-
-		dev_err(info->dev, "unknown pull setting\n");
-		return -EIO;
+		return rockchip_pull_list[pull_type][data];
 	default:
 		dev_err(info->dev, "unsupported pinctrl type\n");
 		return -EINVAL;
@@ -1076,7 +1144,7 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
 	struct rockchip_pinctrl *info = bank->drvdata;
 	struct rockchip_pin_ctrl *ctrl = info->ctrl;
 	struct regmap *regmap;
-	int reg, ret;
+	int reg, ret, i, pull_type;
 	unsigned long flags;
 	u8 bit;
 	u32 data, rmask;
@@ -1105,30 +1173,28 @@ static int rockchip_set_pull(struct rockchip_pin_bank *bank,
 	case RK3288:
 	case RK3368:
 	case RK3399:
+		pull_type = bank->pull_type[pin_num / 8];
+		ret = -EINVAL;
+		for (i = 0; i < ARRAY_SIZE(rockchip_pull_list[pull_type]);
+			i++) {
+			if (rockchip_pull_list[pull_type][i] == pull) {
+				ret = i;
+				break;
+			}
+		}
+
+		if (ret < 0) {
+			dev_err(info->dev, "unsupported pull setting %d\n",
+				pull);
+			return ret;
+		}
+
 		spin_lock_irqsave(&bank->slock, flags);
 
 		/* enable the write to the equivalent lower bits */
 		data = ((1 << RK3188_PULL_BITS_PER_PIN) - 1) << (bit + 16);
 		rmask = data | (data >> 16);
-
-		switch (pull) {
-		case PIN_CONFIG_BIAS_DISABLE:
-			break;
-		case PIN_CONFIG_BIAS_PULL_UP:
-			data |= (1 << bit);
-			break;
-		case PIN_CONFIG_BIAS_PULL_DOWN:
-			data |= (2 << bit);
-			break;
-		case PIN_CONFIG_BIAS_BUS_HOLD:
-			data |= (3 << bit);
-			break;
-		default:
-			spin_unlock_irqrestore(&bank->slock, flags);
-			dev_err(info->dev, "unsupported pull setting %d\n",
-				pull);
-			return -EINVAL;
-		}
+		data |= (ret << bit);
 
 		ret = regmap_update_bits(regmap, reg, rmask, data);
 
@@ -2552,19 +2618,24 @@ static struct rockchip_pin_ctrl rk3368_pin_ctrl = {
 };
 
 static struct rockchip_pin_bank rk3399_pin_banks[] = {
-	PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(0, 32, "gpio0", IOMUX_SOURCE_PMU,
-					IOMUX_SOURCE_PMU,
-					IOMUX_SOURCE_PMU,
-					IOMUX_SOURCE_PMU,
-					DRV_TYPE_IO_1V8_ONLY,
-					DRV_TYPE_IO_1V8_ONLY,
-					DRV_TYPE_IO_DEFAULT,
-					DRV_TYPE_IO_DEFAULT,
-					0x0,
-					0x8,
-					-1,
-					-1
-					),
+	PIN_BANK_IOMUX_FLAGS_DRV_FLAGS_OFFSET_PULL_FLAGS(0, 32, "gpio0",
+							 IOMUX_SOURCE_PMU,
+							 IOMUX_SOURCE_PMU,
+							 IOMUX_SOURCE_PMU,
+							 IOMUX_SOURCE_PMU,
+							 DRV_TYPE_IO_1V8_ONLY,
+							 DRV_TYPE_IO_1V8_ONLY,
+							 DRV_TYPE_IO_DEFAULT,
+							 DRV_TYPE_IO_DEFAULT,
+							 0x0,
+							 0x8,
+							 -1,
+							 -1,
+							 PULL_TYPE_IO_1V8_ONLY,
+							 PULL_TYPE_IO_1V8_ONLY,
+							 PULL_TYPE_IO_DEFAULT,
+							 PULL_TYPE_IO_DEFAULT
+							),
 	PIN_BANK_IOMUX_DRV_FLAGS_OFFSET(1, 32, "gpio1", IOMUX_SOURCE_PMU,
 					IOMUX_SOURCE_PMU,
 					IOMUX_SOURCE_PMU,
@@ -2578,11 +2649,15 @@ static struct rockchip_pin_bank rk3399_pin_banks[] = {
 					0x30,
 					0x38
 					),
-	PIN_BANK_DRV_FLAGS(2, 32, "gpio2", DRV_TYPE_IO_1V8_OR_3V0,
-			   DRV_TYPE_IO_1V8_OR_3V0,
-			   DRV_TYPE_IO_1V8_ONLY,
-			   DRV_TYPE_IO_1V8_ONLY
-			   ),
+	PIN_BANK_DRV_FLAGS_PULL_FLAGS(2, 32, "gpio2", DRV_TYPE_IO_1V8_OR_3V0,
+				      DRV_TYPE_IO_1V8_OR_3V0,
+				      DRV_TYPE_IO_1V8_ONLY,
+				      DRV_TYPE_IO_1V8_ONLY,
+				      PULL_TYPE_IO_DEFAULT,
+				      PULL_TYPE_IO_DEFAULT,
+				      PULL_TYPE_IO_1V8_ONLY,
+				      PULL_TYPE_IO_1V8_ONLY
+				      ),
 	PIN_BANK_DRV_FLAGS(3, 32, "gpio3", DRV_TYPE_IO_3V3_ONLY,
 			   DRV_TYPE_IO_3V3_ONLY,
 			   DRV_TYPE_IO_3V3_ONLY,
-- 
1.9.1



From dianders at chromium.org  Tue May 10 20:50:12 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 10 May 2016 20:50:12 -0700
Subject: [PATCH 2/2] dt-bindings: rockchip-dw-mshc: add rockchip,
 default-drv-phase
In-Reply-To: <e202f663-88d7-693b-a765-c130e68d1c2d@rock-chips.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
 <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=WSkBwBjVsRoDsfjD+sNfR70mKGRA0khjPKKW0zS2=PTw@mail.gmail.com>
 <b15dcb4f-1584-8219-2fe0-97eecb0c64a6@rock-chips.com>
 <CAD=FV=XToSzqSh=SShHuQU9W_m7gfyQn8wRXkLy79t+tnqZknA@mail.gmail.com>
 <1f2f43c7-2672-e448-eddb-2d613bb8dc48@rock-chips.com>
 <CAD=FV=UGbrJRyUbbgzbcYf9GjPG+Fh_gpQ3rX2G=wi2w5Lw=Sg@mail.gmail.com>
 <e202f663-88d7-693b-a765-c130e68d1c2d@rock-chips.com>
Message-ID: <CAD=FV=UyYCqMYKScjVEASrbzO75014kPCEt39uOSTsgq9M==YQ@mail.gmail.com>

Hi,

On Tue, May 10, 2016 at 7:50 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>> maybe. But I think 180(downside) is the better.
>
>
> NAK my previous comments here. Downside is better for SRD, but won't
> work for DDR mode. When running in DDR mode, we should use 90 instead.
>
> So let me elaborate a bit more here.
> For DDR mode, one single clk cycle should sending two data bits outside
> to the devices. We need a hold time for both. If 180 is used, the first
> bit occurs around the downside area, which won't be sampled by devices
> on the upside.  So on the upside, the devices will see a zero bit if you
> actually send a one-bit, which makes the devices  generate CRC finally.
>
>
> For this above, 180 for all SDR mode is ok, but 90 should be deployed
> for DDR mode. So simply checking the timing to hardcode it should be
> fine.

OK, I sent out a patch for 180 always.  I can send v2 to use 90 for
DDR modes tomorrow.  ...or feel free to post that yourself if you
want.

We want 90 for all DDR modes?  So MMC_TIMING_UHS_DDR50,
MMC_TIMING_MMC_DDR52, MMC_TIMING_MMC_HS400? (not that we support HS400
in dw_mmc on Rockchip).

-Doug


From dianders at chromium.org  Tue May 10 21:00:57 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 10 May 2016 21:00:57 -0700
Subject: [PATCH v2] pinctrl: rockchip: fix pull setting error for rk3399
In-Reply-To: <1462937968-4952-1-git-send-email-wxt@rock-chips.com>
References: <1462937968-4952-1-git-send-email-wxt@rock-chips.com>
Message-ID: <CAD=FV=UXFj9Pq64Ksf8fWtCTffujuZjh8JR4OEmR7=vMTycP1Q@mail.gmail.com>

Caesar,

On Tue, May 10, 2016 at 8:39 PM, Caesar Wang <wxt at rock-chips.com> wrote:
> From: David Wu <david.wu at rock-chips.com>
>
> This patch fixes the pinctrl pull bias setting, since the pull up/down
> setting is the contrary for gpio0(just the gpio0a and gpio0b) and
> gpio2(just the gpio2c and gpio2d).
>
> From the TRM said, the gpio0a pull polarity setting:
> gpio0a_p
> GPIO0A PE/PS programmation section, every
> GPIO bit corresponding to 2bits[PS:PE]
> 2'b00: Z(Normal operation);
> 2'b11: weak 1(pull-up);
> 2'b01: weak 0(pull-down);
> 2'b10: Z(Normal operation);
>
> Then, the other gpios setting as the following:
> gpio1a_p (e.g.: gpio1, gpio2a, gpio2b, gpio3...)
> GPIO1A PU/PD programmation section, every
> GPIO bit corresponding to 2bits
> 2'b00: Z(Normal operation);
> 2'b01: weak 1(pull-up);
> 2'b10: weak 0(pull-down);
> 2'b11: Z(Normal operation);
>
> For example,(rk3399evb board)
> sdmmc_cd --->gpio0_a7
> localhost / # io -r -4 0xff320040
> ff320040: 00004d5f
> In general,the value should be 0x0000cd5f since the pin has been set
> in the dts.
>
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Linus Walleij <linus.walleij at linaro.org>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Cc: linux-gpio at vger.kernel.org
> ---
>
> Changes in v2:
> - As Doug commnets on https://patchwork.kernel.org/patch/9056961/
> - update the commit for gpio2.
> - change the print error messgae.
>
>  drivers/pinctrl/pinctrl-rockchip.c | 179 ++++++++++++++++++++++++++-----------
>  1 file changed, 127 insertions(+), 52 deletions(-)

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From david.wu at rock-chips.com  Tue May 10 12:24:05 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed, 11 May 2016 03:24:05 +0800
Subject: [PATCH v8 1/8] i2c: rk3x: add documentation to fields in "struct
 rk3x_i2c"
In-Reply-To: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462908252-27016-2-git-send-email-david.wu@rock-chips.com>

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
---
Change in v8:
- none

 drivers/i2c/busses/i2c-rk3x.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 80bed02..7e45d51 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -90,6 +90,26 @@ struct rk3x_i2c_soc_data {
 	int grf_offset;
 };
 
+/**
+ * struct rk3x_i2c - private data of the controller
+ * @adap: corresponding I2C adapter
+ * @dev: device for this controller
+ * @soc_data: related soc data struct
+ * @regs: virtual memory area
+ * @clk: clock of i2c bus
+ * @clk_rate_nb: i2c clk rate change notify
+ * @t: I2C known timing information
+ * @lock: spinlock for the i2c bus
+ * @wait: the waitqueue to wait for i2c transfer
+ * @busy: the condition for the event to wait for
+ * @msg: current i2c message
+ * @addr: addr of i2c slave device
+ * @mode: mode of i2c transfer
+ * @is_last_msg: flag determines whether it is the last msg in this transfer
+ * @state: state of i2c transfer
+ * @processed: byte length which has been send or received
+ * @error: error code for i2c transfer
+ */
 struct rk3x_i2c {
 	struct i2c_adapter adap;
 	struct device *dev;
@@ -116,7 +136,7 @@ struct rk3x_i2c {
 
 	/* I2C state machine */
 	enum rk3x_i2c_state state;
-	unsigned int processed; /* sent/received bytes */
+	unsigned int processed;
 	int error;
 };
 
-- 
1.9.1




From david.wu at rock-chips.com  Tue May 10 12:24:06 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed, 11 May 2016 03:24:06 +0800
Subject: [PATCH v8 2/8] i2c: rk3x: use struct "rk3x_i2c_calced_timings"
In-Reply-To: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462908252-27016-3-git-send-email-david.wu@rock-chips.com>

The "div_high" and "div_low" values are always used together.  Group them
into a structure to make it easier to pass them both around.  This
structure also provides a place for future calculated timings.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
---
Change in v8:
- add commit description.

 drivers/i2c/busses/i2c-rk3x.c | 55 +++++++++++++++++++++++++------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 7e45d51..1e2677a 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -75,6 +75,16 @@ enum {
 #define WAIT_TIMEOUT      1000 /* ms */
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
+/**
+ * struct rk3x_i2c_calced_timings:
+ * @div_low: Divider output for low
+ * @div_high: Divider output for high
+ */
+struct rk3x_i2c_calced_timings {
+	unsigned long div_low;
+	unsigned long div_high;
+};
+
 enum rk3x_i2c_state {
 	STATE_IDLE,
 	STATE_START,
@@ -454,9 +464,8 @@ out:
  * Calculate divider values for desired SCL frequency
  *
  * @clk_rate: I2C input clock rate
- * @t: Known I2C timing information.
- * @div_low: Divider output for low
- * @div_high: Divider output for high
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
  *
  * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
@@ -464,8 +473,7 @@ out:
  */
 static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 			      struct i2c_timings *t,
-			      unsigned long *div_low,
-			      unsigned long *div_high)
+			      struct rk3x_i2c_calced_timings *t_calc)
 {
 	unsigned long spec_min_low_ns, spec_min_high_ns;
 	unsigned long spec_setup_start, spec_max_data_hold_ns;
@@ -572,8 +580,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 		 * Time needed to meet hold requirements is important.
 		 * Just use that.
 		 */
-		*div_low = min_low_div;
-		*div_high = min_high_div;
+		t_calc->div_low = min_low_div;
+		t_calc->div_high = min_high_div;
 	} else {
 		/*
 		 * We've got to distribute some time among the low and high
@@ -602,25 +610,25 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 
 		/* Give low the "ideal" and give high whatever extra is left */
 		extra_low_div = ideal_low_div - min_low_div;
-		*div_low = ideal_low_div;
-		*div_high = min_high_div + (extra_div - extra_low_div);
+		t_calc->div_low = ideal_low_div;
+		t_calc->div_high = min_high_div + (extra_div - extra_low_div);
 	}
 
 	/*
 	 * Adjust to the fact that the hardware has an implicit "+1".
 	 * NOTE: Above calculations always produce div_low > 0 and div_high > 0.
 	 */
-	*div_low = *div_low - 1;
-	*div_high = *div_high - 1;
+	t_calc->div_low--;
+	t_calc->div_high--;
 
 	/* Maximum divider supported by hw is 0xffff */
-	if (*div_low > 0xffff) {
-		*div_low = 0xffff;
+	if (t_calc->div_low > 0xffff) {
+		t_calc->div_low = 0xffff;
 		ret = -EINVAL;
 	}
 
-	if (*div_high > 0xffff) {
-		*div_high = 0xffff;
+	if (t_calc->div_high > 0xffff) {
+		t_calc->div_high = 0xffff;
 		ret = -EINVAL;
 	}
 
@@ -630,19 +638,21 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 {
 	struct i2c_timings *t = &i2c->t;
-	unsigned long div_low, div_high;
+	struct rk3x_i2c_calced_timings calc;
 	u64 t_low_ns, t_high_ns;
 	int ret;
 
-	ret = rk3x_i2c_calc_divs(clk_rate, t, &div_low, &div_high);
+	ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
 	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
 
 	clk_enable(i2c->clk);
-	i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV);
+	i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
+		   REG_CLKDIV);
 	clk_disable(i2c->clk);
 
-	t_low_ns = div_u64(((u64)div_low + 1) * 8 * 1000000000, clk_rate);
-	t_high_ns = div_u64(((u64)div_high + 1) * 8 * 1000000000, clk_rate);
+	t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
+	t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
+			    clk_rate);
 	dev_dbg(i2c->dev,
 		"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
 		clk_rate / 1000,
@@ -672,12 +682,11 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
 {
 	struct clk_notifier_data *ndata = data;
 	struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
-	unsigned long div_low, div_high;
+	struct rk3x_i2c_calced_timings calc;
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
-		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t,
-				       &div_low, &div_high) != 0)
+		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0)
 			return NOTIFY_STOP;
 
 		/* scale up */
-- 
1.9.1




From david.wu at rock-chips.com  Tue May 10 12:24:07 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed, 11 May 2016 03:24:07 +0800
Subject: [PATCH v8 3/8] i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
In-Reply-To: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462908252-27016-4-git-send-email-david.wu@rock-chips.com>

Call rk3x_i2c_setup() before rk3x_i2c_start()
and the last thing in setup was to clean the IPD,
so no reason to do it at the beginning of start.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
---
Change in v8:
- none

 drivers/i2c/busses/i2c-rk3x.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 1e2677a..9eeb4e5 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -174,7 +174,6 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
 	u32 val;
 
-	rk3x_i2c_clean_ipd(i2c);
 	i2c_writel(i2c, REG_INT_START, REG_IEN);
 
 	/* enable adapter with correct mode, send START condition */
-- 
1.9.1




From david.wu at rock-chips.com  Tue May 10 12:24:08 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed, 11 May 2016 03:24:08 +0800
Subject: [PATCH v8 4/8] i2c: rk3x: Change SoC data to not use array
In-Reply-To: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462908252-27016-5-git-send-email-david.wu@rock-chips.com>

Specifying the i2c SoC data in an array provides very little benefit and
gets unwieldly / confusing as the array grows since the next bit of code
needs to refer to elements in the array by their raw integral index.

Let's just create a single 'static const' structure for each SoC so that
we can refer to these structures by ID.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Suggested-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
---
Change in v8:
- add commit description.

 drivers/i2c/busses/i2c-rk3x.c | 38 ++++++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 9eeb4e5..d7a871f 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -864,17 +864,39 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
 	.functionality		= rk3x_i2c_func,
 };
 
-static struct rk3x_i2c_soc_data soc_data[3] = {
-	{ .grf_offset = 0x154 }, /* rk3066 */
-	{ .grf_offset = 0x0a4 }, /* rk3188 */
-	{ .grf_offset = -1 },    /* no I2C switching needed */
+static const struct rk3x_i2c_soc_data rk3066_soc_data = {
+	.grf_offset = 0x154,
+};
+
+static const struct rk3x_i2c_soc_data rk3188_soc_data = {
+	.grf_offset = 0x0a4,
+};
+
+static const struct rk3x_i2c_soc_data rk3228_soc_data = {
+	.grf_offset = -1,
+};
+
+static const struct rk3x_i2c_soc_data rk3288_soc_data = {
+	.grf_offset = -1,
 };
 
 static const struct of_device_id rk3x_i2c_match[] = {
-	{ .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] },
-	{ .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] },
-	{ .compatible = "rockchip,rk3228-i2c", .data = (void *)&soc_data[2] },
-	{ .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] },
+	{
+		.compatible = "rockchip,rk3066-i2c",
+		.data = (void *)&rk3066_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3188-i2c",
+		.data = (void *)&rk3188_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3228-i2c",
+		.data = (void *)&rk3228_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3288-i2c",
+		.data = (void *)&rk3288_soc_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
-- 
1.9.1




From david.wu at rock-chips.com  Tue May 10 12:30:47 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed, 11 May 2016 03:30:47 +0800
Subject: [PATCH v8 6/8] dt-bindings: i2c: rk3x: add support for rk3399
In-Reply-To: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462908647-27236-1-git-send-email-david.wu@rock-chips.com>

The bus clock and function clock are separated at rk3399,
and others use one clock as the bus clock and function clock.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
---
Change in v8:
- remove error description.

 Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
index 0b4a85f..5429301 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
@@ -6,10 +6,20 @@ RK3xxx SoCs.
 Required properties :
 
  - reg : Offset and length of the register set for the device
- - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c",
-		"rockchip,rk3228-i2c" or "rockchip,rk3288-i2c".
+ - compatible: should be one of the following:
+   - "rockchip,rk3066-i2c": for rk3066
+   - "rockchip,rk3188-i2c": for rk3188
+   - "rockchip,rk3228-i2c": for rk3228
+   - "rockchip,rk3288-i2c": for rk3288
+   - "rockchip,rk3399-i2c": for rk3399
  - interrupts : interrupt number
- - clocks : parent clock
+ - clocks: See ../clock/clock-bindings.txt
+   - For older hardware (rk3066, rk3188, rk3228, rk3288):
+     - There is one clock that's used both to derive the functional clock
+       for the device and as the bus clock.
+   - For newer hardware (rk3399): specified by name
+     - "i2c": REQUIRED. This is used to derive the functional clock.
+     - "pclk": REQUIRED. This is the bus clock.
 
 Required on RK3066, RK3188 :
 
-- 
1.9.1




From david.wu at rock-chips.com  Tue May 10 12:31:38 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed, 11 May 2016 03:31:38 +0800
Subject: [PATCH v8 7/8] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462908698-27284-1-git-send-email-david.wu@rock-chips.com>

- new method to caculate i2c timings for rk3399:
  There was an timing issue about "repeated start" time at the I2C
  controller of version0, controller appears to drop SDA at .875x (7/8)
  programmed clk high. On version 1 of the controller, the rule(.875x)
  isn't enough to meet tSU;STA
  requirements on 100k's Standard-mode. To resolve this issue,
  sda_update_config, start_setup_config and stop_setup_config for I2C
  timing information are added, new rules are designed to calculate
  the timing information at new v1.
- pclk and function clk are separated at rk3399

Signed-off-by: David Wu <david.wu at rock-chips.com>
---
Changes in v8:
- update tuning in RKI2C_CON register by doing a read-modify-write (Doug)
- new method to use pclk and clk (Doug)

Changes in v7:
- transform into a 9 series patches (Doug)
- drop highspeed with mastercode, and support fast-mode plus (Doug)

 drivers/i2c/busses/i2c-rk3x.c | 289 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 270 insertions(+), 19 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 9791797..25ed1ad 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -58,6 +58,12 @@ enum {
 #define REG_CON_LASTACK   BIT(5) /* 1: send NACK after last received byte */
 #define REG_CON_ACTACK    BIT(6) /* 1: stop if NACK is received */
 
+#define REG_CON_TUNING_MASK GENMASK(15, 8)
+
+#define REG_CON_SDA_CFG(cfg) ((cfg) << 8)
+#define REG_CON_STA_CFG(cfg) ((cfg) << 12)
+#define REG_CON_STO_CFG(cfg) ((cfg) << 14)
+
 /* REG_MRXADDR bits */
 #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
 
@@ -77,40 +83,62 @@ enum {
 
 /**
  * struct i2c_spec_values:
+ * @min_hold_start_ns: min hold time (repeated) START condition
  * @min_low_ns: min LOW period of the SCL clock
  * @min_high_ns: min HIGH period of the SCL cloc
  * @min_setup_start_ns: min set-up time for a repeated START conditio
  * @max_data_hold_ns: max data hold time
+ * @min_data_setup_ns: min data set-up time
+ * @min_setup_stop_ns: min set-up time for STOP condition
+ * @min_hold_buffer_ns: min bus free time between a STOP and
+ * START condition
  */
 struct i2c_spec_values {
+	unsigned long min_hold_start_ns;
 	unsigned long min_low_ns;
 	unsigned long min_high_ns;
 	unsigned long min_setup_start_ns;
 	unsigned long max_data_hold_ns;
+	unsigned long min_data_setup_ns;
+	unsigned long min_setup_stop_ns;
+	unsigned long min_hold_buffer_ns;
 };
 
 static const struct i2c_spec_values standard_mode_spec = {
+	.min_hold_start_ns = 4000,
 	.min_low_ns = 4700,
 	.min_high_ns = 4000,
 	.min_setup_start_ns = 4700,
 	.max_data_hold_ns = 3450,
+	.min_data_setup_ns = 250,
+	.min_setup_stop_ns = 4000,
+	.min_hold_buffer_ns = 4700,
 };
 
 static const struct i2c_spec_values fast_mode_spec = {
+	.min_hold_start_ns = 600,
 	.min_low_ns = 1300,
 	.min_high_ns = 600,
 	.min_setup_start_ns = 600,
 	.max_data_hold_ns = 900,
+	.min_data_setup_ns = 100,
+	.min_setup_stop_ns = 600,
+	.min_hold_buffer_ns = 1300,
 };
 
 /**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
  * @div_high: Divider output for high
+ * @tuning: Used to adjust setup/hold data time,
+ * setup/hold start time and setup stop time for
+ * v1's calc_timings, the tuning should all be 0
+ * for old hardware anyone using v0's calc_timings.
  */
 struct rk3x_i2c_calced_timings {
 	unsigned long div_low;
 	unsigned long div_high;
+	unsigned int tuning;
 };
 
 enum rk3x_i2c_state {
@@ -123,9 +151,12 @@ enum rk3x_i2c_state {
 
 /**
  * @grf_offset: offset inside the grf regmap for setting the i2c type
+ * @calc_timings: Callback function for i2c timing information calculated
  */
 struct rk3x_i2c_soc_data {
 	int grf_offset;
+	int (*calc_timings)(unsigned long, struct i2c_timings *,
+			    struct rk3x_i2c_calced_timings *);
 };
 
 /**
@@ -134,7 +165,8 @@ struct rk3x_i2c_soc_data {
  * @dev: device for this controller
  * @soc_data: related soc data struct
  * @regs: virtual memory area
- * @clk: clock of i2c bus
+ * @clk: function clk for rk3399 or function & Bus clks for others
+ * @pclk: Bus clk for rk3399
  * @clk_rate_nb: i2c clk rate change notify
  * @t: I2C known timing information
  * @lock: spinlock for the i2c bus
@@ -156,6 +188,7 @@ struct rk3x_i2c {
 	/* Hardware resources */
 	void __iomem *regs;
 	struct clk *clk;
+	struct clk *pclk;
 	struct notifier_block clk_rate_nb;
 
 	/* Settings */
@@ -200,12 +233,12 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
  */
 static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
-	u32 val;
+	u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
 
 	i2c_writel(i2c, REG_INT_START, REG_IEN);
 
 	/* enable adapter with correct mode, send START condition */
-	val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
+	val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
 
 	/* if we want to react to NACK, set ACTACK bit */
 	if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
@@ -513,9 +546,9 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
  * a best-effort divider value is returned in divs. If the target rate is
  * too high, we silently use the highest possible rate.
  */
-static int rk3x_i2c_calc_divs(unsigned long clk_rate,
-			      struct i2c_timings *t,
-			      struct rk3x_i2c_calced_timings *t_calc)
+static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
+				    struct i2c_timings *t,
+				    struct rk3x_i2c_calced_timings *t_calc)
 {
 	unsigned long min_low_ns, min_high_ns;
 	unsigned long max_low_ns, min_total_ns;
@@ -661,20 +694,189 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	return ret;
 }
 
+/**
+ * Calculate timing values for desired SCL frequency
+ *
+ * @clk_rate: I2C input clock rate
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
+
+ * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
+ * a best-effort divider value is returned in divs. If the target rate is
+ * too high, we silently use the highest possible rate.
+ * The following formulas are v1's method to calculate timings.
+ *
+ * l = divl + 1;
+ * h = divh + 1;
+ * s = sda_update_config + 1;
+ * u = start_setup_config + 1;
+ * p = stop_setup_config + 1;
+ * T = Tclk_i2c;
+
+ * tHigh = 8 * h * T;
+ * tLow = 8 * l * T;
+
+ * tHD;sda = (l * s + 1) * T;
+ * tSU;sda = [(8 - s) * l + 1] * T;
+ * tI2C = 8 * (l + h) * T;
+
+ * tSU;sta = (8h * u + 1) * T;
+ * tHD;sta = [8h * (u + 1) - 1] * T;
+ * tSU;sto = (8h * p + 1) * T;
+ */
+static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
+				    struct i2c_timings *t,
+				    struct rk3x_i2c_calced_timings *t_calc)
+{
+	unsigned long min_low_ns, min_high_ns, min_total_ns;
+	unsigned long min_setup_start_ns, min_setup_data_ns;
+	unsigned long min_setup_stop_ns, max_hold_data_ns;
+
+	unsigned long clk_rate_khz, scl_rate_khz;
+
+	unsigned long min_low_div, min_high_div;
+
+	unsigned long min_div_for_hold, min_total_div;
+	unsigned long extra_div, extra_low_div;
+	unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg;
+
+	const struct i2c_spec_values *spec;
+	int ret = 0;
+
+	/* Support standard-mode and fast-mode */
+	if (WARN_ON(t->bus_freq_hz > 400000))
+		t->bus_freq_hz = 400000;
+
+	/* prevent scl_rate_khz from becoming 0 */
+	if (WARN_ON(t->bus_freq_hz < 1000))
+		t->bus_freq_hz = 1000;
+
+	/*
+	 * min_low_ns: The minimum number of ns we need to hold low to
+	 *	       meet I2C specification, should include fall time.
+	 * min_high_ns: The minimum number of ns we need to hold high to
+	 *	        meet I2C specification, should include rise time.
+	 */
+	spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+
+	/* calculate min-divh and min-divl */
+	clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
+	scl_rate_khz = t->bus_freq_hz / 1000;
+	min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
+
+	min_high_ns = t->scl_rise_ns + spec->min_high_ns;
+	min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
+
+	min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+	min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
+
+	/*
+	 * Final divh and divl must be greater than 0, otherwise the
+	 * hardware would not output the i2c clk.
+	 */
+	min_high_div = (min_high_div < 1) ? 2 : min_high_div;
+	min_low_div = (min_low_div < 1) ? 2 : min_low_div;
+
+	/* These are the min dividers needed for min hold times. */
+	min_div_for_hold = (min_low_div + min_high_div);
+	min_total_ns = min_low_ns + min_high_ns;
+
+	/*
+	 * This is the maximum divider so we don't go over the maximum.
+	 * We don't round up here (we round down) since this is a maximum.
+	 */
+	 if (min_div_for_hold >= min_total_div) {
+		/*
+		 * Time needed to meet hold requirements is important.
+		 * Just use that.
+		 */
+		t_calc->div_low = min_low_div;
+		t_calc->div_high = min_high_div;
+	} else {
+		/*
+		 * We've got to distribute some time among the low and high
+		 * so we don't run too fast.
+		 * We'll try to split things up by the scale of min_low_div and
+		 * min_high_div, biasing slightly towards having a higher div
+		 * for low (spend more time low).
+		 */
+		extra_div = min_total_div - min_div_for_hold;
+		extra_low_div = DIV_ROUND_UP(min_low_div * extra_div,
+					     min_div_for_hold);
+
+		t_calc->div_low = min_low_div + extra_low_div;
+		t_calc->div_high = min_high_div + (extra_div - extra_low_div);
+	}
+
+	/*
+	 * calculate sda data hold count by the rules, data_upd_st:3
+	 * is a appropriate value to reduce calculated times.
+	 */
+	for (sda_update_cfg = 3; sda_update_cfg > 0; sda_update_cfg--) {
+		max_hold_data_ns =  DIV_ROUND_UP((sda_update_cfg
+						 * (t_calc->div_low) + 1)
+						 * 1000000, clk_rate_khz);
+		min_setup_data_ns =  DIV_ROUND_UP(((8 - sda_update_cfg)
+						 * (t_calc->div_low) + 1)
+						 * 1000000, clk_rate_khz);
+		if ((max_hold_data_ns < spec->max_data_hold_ns) &&
+		    (min_setup_data_ns > spec->min_data_setup_ns))
+			break;
+	}
+
+	/* calculate setup start config */
+	min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns;
+	stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns
+			   - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+	/* calculate setup stop config */
+	min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns;
+	stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns
+			   - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+	t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) |
+			 REG_CON_STA_CFG(--stp_sta_cfg) |
+			 REG_CON_STO_CFG(--stp_sto_cfg);
+
+	t_calc->div_low--;
+	t_calc->div_high--;
+
+	/* Maximum divider supported by hw is 0xffff */
+	if (t_calc->div_low > 0xffff) {
+		t_calc->div_low = 0xffff;
+		ret = -EINVAL;
+	}
+
+	if (t_calc->div_high > 0xffff) {
+		t_calc->div_high = 0xffff;
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 {
 	struct i2c_timings *t = &i2c->t;
 	struct rk3x_i2c_calced_timings calc;
 	u64 t_low_ns, t_high_ns;
+	u32 val;
 	int ret;
 
-	ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
+	ret = i2c->soc_data->calc_timings(clk_rate, t, &calc);
 	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
 
-	clk_enable(i2c->clk);
+	clk_enable(i2c->pclk);
+
 	i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
 		   REG_CLKDIV);
-	clk_disable(i2c->clk);
+
+	val = i2c_readl(i2c, REG_CON);
+	val &= ~REG_CON_TUNING_MASK;
+	val |= calc.tuning;
+	i2c_writel(i2c, val, REG_CON);
+
+	clk_disable(i2c->pclk);
 
 	t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
 	t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
@@ -712,7 +914,13 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
-		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0)
+		/*
+		 * Try the calculation (but don't store the result) ahead of
+		 * time to see if we need to block the clock change.  Timings
+		 * shouldn't actually take effect until rk3x_i2c_adapt_div().
+		 */
+		if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t,
+						&calc) != 0)
 			return NOTIFY_STOP;
 
 		/* scale up */
@@ -822,12 +1030,14 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 {
 	struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
 	unsigned long timeout, flags;
+	u32 val;
 	int ret = 0;
 	int i;
 
 	spin_lock_irqsave(&i2c->lock, flags);
 
 	clk_enable(i2c->clk);
+	clk_enable(i2c->pclk);
 
 	i2c->is_last_msg = false;
 
@@ -861,7 +1071,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 
 			/* Force a STOP condition without interrupt */
 			i2c_writel(i2c, 0, REG_IEN);
-			i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON);
+			val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+			val |= REG_CON_EN | REG_CON_STOP;
+			i2c_writel(i2c, val, REG_CON);
 
 			i2c->state = STATE_IDLE;
 
@@ -875,7 +1087,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 		}
 	}
 
+	clk_disable(i2c->pclk);
 	clk_disable(i2c->clk);
+
 	spin_unlock_irqrestore(&i2c->lock, flags);
 
 	return ret < 0 ? ret : num;
@@ -893,18 +1107,27 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
 
 static const struct rk3x_i2c_soc_data rk3066_soc_data = {
 	.grf_offset = 0x154,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3188_soc_data = {
 	.grf_offset = 0x0a4,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3228_soc_data = {
 	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3288_soc_data = {
 	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3399_soc_data = {
+	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v1_calc_timings,
 };
 
 static const struct of_device_id rk3x_i2c_match[] = {
@@ -924,6 +1147,10 @@ static const struct of_device_id rk3x_i2c_match[] = {
 		.compatible = "rockchip,rk3288-i2c",
 		.data = (void *)&rk3288_soc_data
 	},
+	{
+		.compatible = "rockchip,rk3399-i2c",
+		.data = (void *)&rk3399_soc_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
@@ -963,12 +1190,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 	spin_lock_init(&i2c->lock);
 	init_waitqueue_head(&i2c->wait);
 
-	i2c->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(i2c->clk)) {
-		dev_err(&pdev->dev, "cannot get clock\n");
-		return PTR_ERR(i2c->clk);
-	}
-
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(i2c->regs))
@@ -1022,17 +1243,44 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, i2c);
 
+	if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) {
+		/* Only one clock to use for bus clock and peripheral clock */
+		i2c->clk = devm_clk_get(&pdev->dev, NULL);
+		i2c->pclk = i2c->clk;
+	} else {
+		i2c->clk = devm_clk_get(&pdev->dev, "i2c");
+		i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
+	}
+
+	if (IS_ERR(i2c->clk)) {
+		ret = PTR_ERR(i2c->clk);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret);
+		return ret;
+	}
+	if (IS_ERR(i2c->pclk)) {
+		ret = PTR_ERR(i2c->pclk);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret);
+		return ret;
+	}
+
 	ret = clk_prepare(i2c->clk);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "Could not prepare clock\n");
+		dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret);
 		return ret;
 	}
+	ret = clk_prepare(i2c->pclk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret);
+		goto err_clk;
+	}
 
 	i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
 	ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "Unable to register clock notifier\n");
-		goto err_clk;
+		goto err_pclk;
 	}
 
 	clk_rate = clk_get_rate(i2c->clk);
@@ -1050,6 +1298,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 
 err_clk_notifier:
 	clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+err_pclk:
+	clk_unprepare(i2c->pclk);
 err_clk:
 	clk_unprepare(i2c->clk);
 	return ret;
@@ -1062,6 +1312,7 @@ static int rk3x_i2c_remove(struct platform_device *pdev)
 	i2c_del_adapter(&i2c->adap);
 
 	clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+	clk_unprepare(i2c->pclk);
 	clk_unprepare(i2c->clk);
 
 	return 0;
-- 
1.9.1




From david.wu at rock-chips.com  Tue May 10 12:24:04 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed, 11 May 2016 03:24:04 +0800
Subject: [PATCH v8 0/8] add i2c driver supported for rk3399
Message-ID: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>

There are three points differert from others:
 - new method to caculate i2c timings for rk3399
 - pclk and function clk are separated at rk3399
 - add fast-plus mode supported for rk3399

David Wu (8):
  i2c: rk3x: add documentation to fields in "struct rk3x_i2c"
  i2c: rk3x: use struct "rk3x_i2c_calced_timings"
  i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
  i2c: rk3x: Change SoC data to not use array
  i2c: rk3x: Move spec timing data to "static const" structs
  dt-bindings: i2c: rk3x: add support for rk3399
  i2c: rk3x: add i2c support for rk3399 soc
  i2c: rk3x: support fast-mode plus for rk3399

 Documentation/devicetree/bindings/i2c/i2c-rk3x.txt |  16 +-
 drivers/i2c/busses/i2c-rk3x.c                      | 493 +++++++++++++++++----
 2 files changed, 430 insertions(+), 79 deletions(-)

-- 
1.9.1




From david.wu at rock-chips.com  Tue May 10 12:29:58 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed, 11 May 2016 03:29:58 +0800
Subject: [PATCH v8 5/8] i2c: rk3x: Move spec timing data to "static const"
 structs
In-Reply-To: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462908598-27186-1-git-send-email-david.wu@rock-chips.com>

The i2c timing specs are really just constant data.  There's no reason
to write code to init them, so move them out to structures.  This not
only is a cleaner solution but it will reduce code duplication when we
introduce a new variant of rk3x_i2c_calc_divs() in a future patch.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Suggested-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
---
Changes in v8:
- add commit description.
- remove the spec values that were not needed, then
  introduce the additional values in the rk3399 patch. 

 drivers/i2c/busses/i2c-rk3x.c | 83 ++++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 28 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index d7a871f..9791797 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -76,6 +76,34 @@ enum {
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
 /**
+ * struct i2c_spec_values:
+ * @min_low_ns: min LOW period of the SCL clock
+ * @min_high_ns: min HIGH period of the SCL cloc
+ * @min_setup_start_ns: min set-up time for a repeated START conditio
+ * @max_data_hold_ns: max data hold time
+ */
+struct i2c_spec_values {
+	unsigned long min_low_ns;
+	unsigned long min_high_ns;
+	unsigned long min_setup_start_ns;
+	unsigned long max_data_hold_ns;
+};
+
+static const struct i2c_spec_values standard_mode_spec = {
+	.min_low_ns = 4700,
+	.min_high_ns = 4000,
+	.min_setup_start_ns = 4700,
+	.max_data_hold_ns = 3450,
+};
+
+static const struct i2c_spec_values fast_mode_spec = {
+	.min_low_ns = 1300,
+	.min_high_ns = 600,
+	.min_setup_start_ns = 600,
+	.max_data_hold_ns = 900,
+};
+
+/**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
  * @div_high: Divider output for high
@@ -460,6 +488,21 @@ out:
 }
 
 /**
+ * Get timing values of I2C specification
+ *
+ * @speed: Desired SCL frequency
+ *
+ * Returns: Matched i2c spec values.
+ */
+static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
+{
+	if (speed <= 100000)
+		return &standard_mode_spec;
+	else
+		return &fast_mode_spec;
+}
+
+/**
  * Calculate divider values for desired SCL frequency
  *
  * @clk_rate: I2C input clock rate
@@ -474,10 +517,6 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 			      struct i2c_timings *t,
 			      struct rk3x_i2c_calced_timings *t_calc)
 {
-	unsigned long spec_min_low_ns, spec_min_high_ns;
-	unsigned long spec_setup_start, spec_max_data_hold_ns;
-	unsigned long data_hold_buffer_ns;
-
 	unsigned long min_low_ns, min_high_ns;
 	unsigned long max_low_ns, min_total_ns;
 
@@ -489,6 +528,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	unsigned long min_div_for_hold, min_total_div;
 	unsigned long extra_div, extra_low_div, ideal_low_div;
 
+	unsigned long data_hold_buffer_ns = 50;
+	const struct i2c_spec_values *spec;
 	int ret = 0;
 
 	/* Only support standard-mode and fast-mode */
@@ -511,22 +552,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	 *	 This is because the i2c host on Rockchip holds the data line
 	 *	 for half the low time.
 	 */
-	if (t->bus_freq_hz <= 100000) {
-		/* Standard-mode */
-		spec_min_low_ns = 4700;
-		spec_setup_start = 4700;
-		spec_min_high_ns = 4000;
-		spec_max_data_hold_ns = 3450;
-		data_hold_buffer_ns = 50;
-	} else {
-		/* Fast-mode */
-		spec_min_low_ns = 1300;
-		spec_setup_start = 600;
-		spec_min_high_ns = 600;
-		spec_max_data_hold_ns = 900;
-		data_hold_buffer_ns = 50;
-	}
-	min_high_ns = t->scl_rise_ns + spec_min_high_ns;
+	spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+	min_high_ns = t->scl_rise_ns + spec->min_high_ns;
 
 	/*
 	 * Timings for repeated start:
@@ -536,14 +563,14 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	 * We need to account for those rules in picking our "high" time so
 	 * we meet tSU;STA and tHD;STA times.
 	 */
-	min_high_ns = max(min_high_ns,
-		DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875));
-	min_high_ns = max(min_high_ns,
-		DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start +
-			      t->sda_fall_ns + spec_min_high_ns), 2));
-
-	min_low_ns = t->scl_fall_ns + spec_min_low_ns;
-	max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
+	min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+		(t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875));
+	min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+		(t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns +
+		spec->min_high_ns), 2));
+
+	min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+	max_low_ns =  spec->max_data_hold_ns * 2 - data_hold_buffer_ns;
 	min_total_ns = min_low_ns + min_high_ns;
 
 	/* Adjust to avoid overflow */
-- 
1.9.1




From david.wu at rock-chips.com  Tue May 10 12:33:14 2016
From: david.wu at rock-chips.com (David Wu)
Date: Wed, 11 May 2016 03:33:14 +0800
Subject: [PATCH v8 8/8] i2c: rk3x: support fast-mode plus for rk3399
In-Reply-To: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1462908794-27333-1-git-send-email-david.wu@rock-chips.com>

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
---
Change in v8:
- None

 drivers/i2c/busses/i2c-rk3x.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 25ed1ad..0ba25ee 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -126,6 +126,17 @@ static const struct i2c_spec_values fast_mode_spec = {
 	.min_hold_buffer_ns = 1300,
 };
 
+static const struct i2c_spec_values fast_mode_plus_spec = {
+	.min_hold_start_ns = 260,
+	.min_low_ns = 500,
+	.min_high_ns = 260,
+	.min_setup_start_ns = 260,
+	.max_data_hold_ns = 400,
+	.min_data_setup_ns = 50,
+	.min_setup_stop_ns = 260,
+	.min_hold_buffer_ns = 500,
+};
+
 /**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
@@ -531,8 +542,10 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
 {
 	if (speed <= 100000)
 		return &standard_mode_spec;
-	else
+	else if (speed <= 400000)
 		return &fast_mode_spec;
+	else
+		return &fast_mode_plus_spec;
 }
 
 /**
@@ -743,9 +756,9 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
 	const struct i2c_spec_values *spec;
 	int ret = 0;
 
-	/* Support standard-mode and fast-mode */
-	if (WARN_ON(t->bus_freq_hz > 400000))
-		t->bus_freq_hz = 400000;
+	/* Support standard-mode, fast-mode and fast-mode plus */
+	if (WARN_ON(t->bus_freq_hz > 1000000))
+		t->bus_freq_hz = 1000000;
 
 	/* prevent scl_rate_khz from becoming 0 */
 	if (WARN_ON(t->bus_freq_hz < 1000))
-- 
1.9.1




From heiko at sntech.de  Wed May 11 00:11:00 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Wed, 11 May 2016 09:11 +0200
Subject: [PATCH v2] pinctrl: rockchip: fix pull setting error for rk3399
In-Reply-To: <1462937968-4952-1-git-send-email-wxt@rock-chips.com>
References: <1462937968-4952-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1493162.roERW60dFE@phil>

Am Mittwoch, 11. Mai 2016, 11:39:28 schrieb Caesar Wang:
> From: David Wu <david.wu at rock-chips.com>
> 
> This patch fixes the pinctrl pull bias setting, since the pull up/down
> setting is the contrary for gpio0(just the gpio0a and gpio0b) and
> gpio2(just the gpio2c and gpio2d).
> 
> From the TRM said, the gpio0a pull polarity setting:
> gpio0a_p
> GPIO0A PE/PS programmation section, every
> GPIO bit corresponding to 2bits[PS:PE]
> 2'b00: Z(Normal operation);
> 2'b11: weak 1(pull-up);
> 2'b01: weak 0(pull-down);
> 2'b10: Z(Normal operation);

This could mention gpio2c and gpio2d as well, as the code now does.

Otherwise the patch looks good and I also compared with the TRM, so

Reviewed-by: Heiko Stuebner <heiko at sntech.de>



From shawn.lin at rock-chips.com  Wed May 11 01:25:33 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Wed, 11 May 2016 16:25:33 +0800
Subject: [PATCH 2/2] dt-bindings: rockchip-dw-mshc: add
 rockchip,default-drv-phase
In-Reply-To: <CAD=FV=UyYCqMYKScjVEASrbzO75014kPCEt39uOSTsgq9M==YQ@mail.gmail.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
 <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=WSkBwBjVsRoDsfjD+sNfR70mKGRA0khjPKKW0zS2=PTw@mail.gmail.com>
 <b15dcb4f-1584-8219-2fe0-97eecb0c64a6@rock-chips.com>
 <CAD=FV=XToSzqSh=SShHuQU9W_m7gfyQn8wRXkLy79t+tnqZknA@mail.gmail.com>
 <1f2f43c7-2672-e448-eddb-2d613bb8dc48@rock-chips.com>
 <CAD=FV=UGbrJRyUbbgzbcYf9GjPG+Fh_gpQ3rX2G=wi2w5Lw=Sg@mail.gmail.com>
 <e202f663-88d7-693b-a765-c130e68d1c2d@rock-chips.com>
 <CAD=FV=UyYCqMYKScjVEASrbzO75014kPCEt39uOSTsgq9M==YQ@mail.gmail.com>
Message-ID: <2994d365-2cf2-0990-6c10-2abeebb42eef@rock-chips.com>

On 2016/5/11 11:50, Doug Anderson wrote:
> Hi,
>
> On Tue, May 10, 2016 at 7:50 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>>> maybe. But I think 180(downside) is the better.
>>
>>
>> NAK my previous comments here. Downside is better for SRD, but won't
>> work for DDR mode. When running in DDR mode, we should use 90 instead.
>>
>> So let me elaborate a bit more here.
>> For DDR mode, one single clk cycle should sending two data bits outside
>> to the devices. We need a hold time for both. If 180 is used, the first
>> bit occurs around the downside area, which won't be sampled by devices
>> on the upside.  So on the upside, the devices will see a zero bit if you
>> actually send a one-bit, which makes the devices  generate CRC finally.
>>
>>
>> For this above, 180 for all SDR mode is ok, but 90 should be deployed
>> for DDR mode. So simply checking the timing to hardcode it should be
>> fine.
>
> OK, I sent out a patch for 180 always.  I can send v2 to use 90 for
> DDR modes tomorrow.  ...or feel free to post that yourself if you
> want.
>
> We want 90 for all DDR modes?  So MMC_TIMING_UHS_DDR50,
> MMC_TIMING_MMC_DDR52, MMC_TIMING_MMC_HS400? (not that we support HS400
> in dw_mmc on Rockchip).

Right.

>
> -Doug
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>


-- 
Best Regards
Shawn Lin



From linus.walleij at linaro.org  Wed May 11 01:44:36 2016
From: linus.walleij at linaro.org (Linus Walleij)
Date: Wed, 11 May 2016 10:44:36 +0200
Subject: [PATCH v2] pinctrl: rockchip: fix pull setting error for rk3399
In-Reply-To: <1462937968-4952-1-git-send-email-wxt@rock-chips.com>
References: <1462937968-4952-1-git-send-email-wxt@rock-chips.com>
Message-ID: <CACRpkdasLu0ZtOBuyfE=BG6TwY=-NY7Xksywv3jimNGXyx08AQ@mail.gmail.com>

On Wed, May 11, 2016 at 5:39 AM, Caesar Wang <wxt at rock-chips.com> wrote:

> From: David Wu <david.wu at rock-chips.com>
>
> This patch fixes the pinctrl pull bias setting, since the pull up/down
> setting is the contrary for gpio0(just the gpio0a and gpio0b) and
> gpio2(just the gpio2c and gpio2d).
>
> From the TRM said, the gpio0a pull polarity setting:
> gpio0a_p
> GPIO0A PE/PS programmation section, every
> GPIO bit corresponding to 2bits[PS:PE]
> 2'b00: Z(Normal operation);
> 2'b11: weak 1(pull-up);
> 2'b01: weak 0(pull-down);
> 2'b10: Z(Normal operation);
>
> Then, the other gpios setting as the following:
> gpio1a_p (e.g.: gpio1, gpio2a, gpio2b, gpio3...)
> GPIO1A PU/PD programmation section, every
> GPIO bit corresponding to 2bits
> 2'b00: Z(Normal operation);
> 2'b01: weak 1(pull-up);
> 2'b10: weak 0(pull-down);
> 2'b11: Z(Normal operation);
>
> For example,(rk3399evb board)
> sdmmc_cd --->gpio0_a7
> localhost / # io -r -4 0xff320040
> ff320040: 00004d5f
> In general,the value should be 0x0000cd5f since the pin has been set
> in the dts.
>
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Linus Walleij <linus.walleij at linaro.org>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Cc: linux-gpio at vger.kernel.org
> ---
>
> Changes in v2:
> - As Doug commnets on https://patchwork.kernel.org/patch/9056961/
> - update the commit for gpio2.
> - change the print error messgae.

Patch applied with the Review tags.

Yours,
Linus Walleij


From caesar.upstream at gmail.com  Wed May 11 04:43:06 2016
From: caesar.upstream at gmail.com (Caesar Wang)
Date: Wed, 11 May 2016 19:43:06 +0800
Subject: [PATCH v8 7/8] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <1462908698-27284-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908698-27284-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <57331ACA.5020605@gmail.com>



? 2016?05?11? 03:31, David Wu ??:
> - new method to caculate i2c timings for rk3399:
>    There was an timing issue about "repeated start" time at the I2C
>    controller of version0, controller appears to drop SDA at .875x (7/8)
>    programmed clk high. On version 1 of the controller, the rule(.875x)
>    isn't enough to meet tSU;STA
>    requirements on 100k's Standard-mode. To resolve this issue,
>    sda_update_config, start_setup_config and stop_setup_config for I2C
>    timing information are added, new rules are designed to calculate
>    the timing information at new v1.
> - pclk and function clk are separated at rk3399
>
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> ---
> Changes in v8:
> - update tuning in RKI2C_CON register by doing a read-modify-write (Doug)
> - new method to use pclk and clk (Doug)
>
> Changes in v7:
> - transform into a 9 series patches (Doug)
> - drop highspeed with mastercode, and support fast-mode plus (Doug)

Tested-by: Caesar Wang <wxt at rock-chips.com>
Few comments below:


I picked David's patches up for my rk3399 evb board.
Add the needed i2c devices for dts.

localhost / #modprobe i2c-dev
localhost / # i2cdump -f -y 0 0x1b
No size specified (using byte-data access)
      0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f 0123456789abcdef
00: 18 01 09 21 01 13 01 00 00 00 00 01 01 00 00 00 ???!???....??...
10: 80 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ??..............
20: 00 5f 00 6f ff 00 00 00 10 00 ff 0f ff 02 01 0f ._.o....?..?.???
30: 00 00 01 0f 00 00 02 03 00 00 09 00 00 0c 00 0a ..??..??..?..?.?
40: 00 0c 00 0c 00 07 00 0a 00 0c 00 00 00 5f 00 03 .?.?.?.?.?..._.?
50: 06 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ??..............
60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
70: 00 cf 03 00 28 00 0c 1c 80 19 00 34 12 00 71 00 .??.(.????.4?.q.
80: 10 50 1f ac 00 40 00 49 00 00 c0 44 41 01 00 00 ?P??. at .I..?DA?..
90: 55 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 U...............
a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
f0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
localhost / # i2cset -f -y 0 0x1b 0x90 0xff
localhost / # i2cdump -f -y 0 0x1b |grep 90
  No size specified (using byte-data access)
90: ff 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................

The i2c devices are working for my board.

run:
modprobe i2c-dev; for i in $(seq 0 8); do echo ==BUS $i; i2cdetect -y -q 
$i; done
See the output message,and mesure the i2c frequency.





>
>   drivers/i2c/busses/i2c-rk3x.c | 289 +++++++++++++++++++++++++++++++++++++++---
>   1 file changed, 270 insertions(+), 19 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
> index 9791797..25ed1ad 100644
> --- a/drivers/i2c/busses/i2c-rk3x.c
> +++ b/drivers/i2c/busses/i2c-rk3x.c
> @@ -58,6 +58,12 @@ enum {
>   #define REG_CON_LASTACK   BIT(5) /* 1: send NACK after last received byte */
>   #define REG_CON_ACTACK    BIT(6) /* 1: stop if NACK is received */
>   
> +#define REG_CON_TUNING_MASK GENMASK(15, 8)
> +
> +#define REG_CON_SDA_CFG(cfg) ((cfg) << 8)
> +#define REG_CON_STA_CFG(cfg) ((cfg) << 12)
> +#define REG_CON_STO_CFG(cfg) ((cfg) << 14)
> +
>   /* REG_MRXADDR bits */
>   #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
>   
> @@ -77,40 +83,62 @@ enum {
>   
>   /**
>    * struct i2c_spec_values:
> + * @min_hold_start_ns: min hold time (repeated) START condition
>    * @min_low_ns: min LOW period of the SCL clock
>    * @min_high_ns: min HIGH period of the SCL cloc
>    * @min_setup_start_ns: min set-up time for a repeated START conditio
>    * @max_data_hold_ns: max data hold time
> + * @min_data_setup_ns: min data set-up time
> + * @min_setup_stop_ns: min set-up time for STOP condition
> + * @min_hold_buffer_ns: min bus free time between a STOP and
> + * START condition
>    */
>   struct i2c_spec_values {
> +	unsigned long min_hold_start_ns;
>   	unsigned long min_low_ns;
>   	unsigned long min_high_ns;
>   	unsigned long min_setup_start_ns;
>   	unsigned long max_data_hold_ns;
> +	unsigned long min_data_setup_ns;
> +	unsigned long min_setup_stop_ns;
> +	unsigned long min_hold_buffer_ns;
>   };
>   
>   static const struct i2c_spec_values standard_mode_spec = {
> +	.min_hold_start_ns = 4000,
>   	.min_low_ns = 4700,
>   	.min_high_ns = 4000,
>   	.min_setup_start_ns = 4700,
>   	.max_data_hold_ns = 3450,
> +	.min_data_setup_ns = 250,
> +	.min_setup_stop_ns = 4000,
> +	.min_hold_buffer_ns = 4700,
>   };
>   
>   static const struct i2c_spec_values fast_mode_spec = {
> +	.min_hold_start_ns = 600,
>   	.min_low_ns = 1300,
>   	.min_high_ns = 600,
>   	.min_setup_start_ns = 600,
>   	.max_data_hold_ns = 900,
> +	.min_data_setup_ns = 100,
> +	.min_setup_stop_ns = 600,
> +	.min_hold_buffer_ns = 1300,
>   };
>   
>   /**
>    * struct rk3x_i2c_calced_timings:
>    * @div_low: Divider output for low
>    * @div_high: Divider output for high
> + * @tuning: Used to adjust setup/hold data time,
> + * setup/hold start time and setup stop time for
> + * v1's calc_timings, the tuning should all be 0
> + * for old hardware anyone using v0's calc_timings.
>    */
>   struct rk3x_i2c_calced_timings {
>   	unsigned long div_low;
>   	unsigned long div_high;
> +	unsigned int tuning;
>   };
>   
>   enum rk3x_i2c_state {
> @@ -123,9 +151,12 @@ enum rk3x_i2c_state {
>   
>   /**
>    * @grf_offset: offset inside the grf regmap for setting the i2c type
> + * @calc_timings: Callback function for i2c timing information calculated
>    */
>   struct rk3x_i2c_soc_data {
>   	int grf_offset;
> +	int (*calc_timings)(unsigned long, struct i2c_timings *,
> +			    struct rk3x_i2c_calced_timings *);
>   };
>   
>   /**
> @@ -134,7 +165,8 @@ struct rk3x_i2c_soc_data {
>    * @dev: device for this controller
>    * @soc_data: related soc data struct
>    * @regs: virtual memory area
> - * @clk: clock of i2c bus
> + * @clk: function clk for rk3399 or function & Bus clks for others
> + * @pclk: Bus clk for rk3399
>    * @clk_rate_nb: i2c clk rate change notify
>    * @t: I2C known timing information
>    * @lock: spinlock for the i2c bus
> @@ -156,6 +188,7 @@ struct rk3x_i2c {
>   	/* Hardware resources */
>   	void __iomem *regs;
>   	struct clk *clk;
> +	struct clk *pclk;
>   	struct notifier_block clk_rate_nb;
>   
>   	/* Settings */
> @@ -200,12 +233,12 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
>    */
>   static void rk3x_i2c_start(struct rk3x_i2c *i2c)
>   {
> -	u32 val;
> +	u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
>   
>   	i2c_writel(i2c, REG_INT_START, REG_IEN);
>   
>   	/* enable adapter with correct mode, send START condition */
> -	val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
> +	val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
>   
>   	/* if we want to react to NACK, set ACTACK bit */
>   	if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
> @@ -513,9 +546,9 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
>    * a best-effort divider value is returned in divs. If the target rate is
>    * too high, we silently use the highest possible rate.
>    */
> -static int rk3x_i2c_calc_divs(unsigned long clk_rate,
> -			      struct i2c_timings *t,
> -			      struct rk3x_i2c_calced_timings *t_calc)
> +static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
> +				    struct i2c_timings *t,
> +				    struct rk3x_i2c_calced_timings *t_calc)
>   {
>   	unsigned long min_low_ns, min_high_ns;
>   	unsigned long max_low_ns, min_total_ns;
> @@ -661,20 +694,189 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
>   	return ret;
>   }
>   
> +/**
> + * Calculate timing values for desired SCL frequency
> + *
> + * @clk_rate: I2C input clock rate
> + * @t: Known I2C timing information
> + * @t_calc: Caculated rk3x private timings that would be written into regs
> +

miss the '* ' , i guess
> + * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
> + * a best-effort divider value is returned in divs. If the target rate is
> + * too high, we silently use the highest possible rate.
> + * The following formulas are v1's method to calculate timings.
> + *
> + * l = divl + 1;
> + * h = divh + 1;
> + * s = sda_update_config + 1;
> + * u = start_setup_config + 1;
> + * p = stop_setup_config + 1;
> + * T = Tclk_i2c;
> +

Ditto
> + * tHigh = 8 * h * T;
> + * tLow = 8 * l * T;
> +

Ditto
> + * tHD;sda = (l * s + 1) * T;
> + * tSU;sda = [(8 - s) * l + 1] * T;
> + * tI2C = 8 * (l + h) * T;
> +

Ditto
> + * tSU;sta = (8h * u + 1) * T;
> + * tHD;sta = [8h * (u + 1) - 1] * T;
> + * tSU;sto = (8h * p + 1) * T;
> + */
> +static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
> +				    struct i2c_timings *t,
> +				    struct rk3x_i2c_calced_timings *t_calc)
> +{
> +	unsigned long min_low_ns, min_high_ns, min_total_ns;
> +	unsigned long min_setup_start_ns, min_setup_data_ns;
> +	unsigned long min_setup_stop_ns, max_hold_data_ns;
> +
> +	unsigned long clk_rate_khz, scl_rate_khz;
> +
> +	unsigned long min_low_div, min_high_div;
> +
> +	unsigned long min_div_for_hold, min_total_div;
> +	unsigned long extra_div, extra_low_div;
> +	unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg;
> +
> +	const struct i2c_spec_values *spec;
> +	int ret = 0;
> +
> +	/* Support standard-mode and fast-mode */
> +	if (WARN_ON(t->bus_freq_hz > 400000))
> +		t->bus_freq_hz = 400000;
> +
> +	/* prevent scl_rate_khz from becoming 0 */
> +	if (WARN_ON(t->bus_freq_hz < 1000))
> +		t->bus_freq_hz = 1000;
> +
> +	/*
> +	 * min_low_ns: The minimum number of ns we need to hold low to
> +	 *	       meet I2C specification, should include fall time.
> +	 * min_high_ns: The minimum number of ns we need to hold high to
> +	 *	        meet I2C specification, should include rise time.
> +	 */
> +	spec = rk3x_i2c_get_spec(t->bus_freq_hz);
> +
> +	/* calculate min-divh and min-divl */
> +	clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
> +	scl_rate_khz = t->bus_freq_hz / 1000;
> +	min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
> +
> +	min_high_ns = t->scl_rise_ns + spec->min_high_ns;
> +	min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
> +
> +	min_low_ns = t->scl_fall_ns + spec->min_low_ns;
> +	min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
> +
> +	/*
> +	 * Final divh and divl must be greater than 0, otherwise the
> +	 * hardware would not output the i2c clk.
> +	 */
> +	min_high_div = (min_high_div < 1) ? 2 : min_high_div;
> +	min_low_div = (min_low_div < 1) ? 2 : min_low_div;
> +
> +	/* These are the min dividers needed for min hold times. */
> +	min_div_for_hold = (min_low_div + min_high_div);
> +	min_total_ns = min_low_ns + min_high_ns;
> +
> +	/*
> +	 * This is the maximum divider so we don't go over the maximum.
> +	 * We don't round up here (we round down) since this is a maximum.
> +	 */
> +	 if (min_div_for_hold >= min_total_div) {
> +		/*
> +		 * Time needed to meet hold requirements is important.
> +		 * Just use that.
> +		 */
> +		t_calc->div_low = min_low_div;
> +		t_calc->div_high = min_high_div;
> +	} else {
> +		/*
> +		 * We've got to distribute some time among the low and high
> +		 * so we don't run too fast.
> +		 * We'll try to split things up by the scale of min_low_div and
> +		 * min_high_div, biasing slightly towards having a higher div
> +		 * for low (spend more time low).
> +		 */
> +		extra_div = min_total_div - min_div_for_hold;
> +		extra_low_div = DIV_ROUND_UP(min_low_div * extra_div,
> +					     min_div_for_hold);
> +
> +		t_calc->div_low = min_low_div + extra_low_div;
> +		t_calc->div_high = min_high_div + (extra_div - extra_low_div);
> +	}
> +
> +	/*
> +	 * calculate sda data hold count by the rules, data_upd_st:3
> +	 * is a appropriate value to reduce calculated times.
> +	 */
> +	for (sda_update_cfg = 3; sda_update_cfg > 0; sda_update_cfg--) {
> +		max_hold_data_ns =  DIV_ROUND_UP((sda_update_cfg
> +						 * (t_calc->div_low) + 1)
> +						 * 1000000, clk_rate_khz);
> +		min_setup_data_ns =  DIV_ROUND_UP(((8 - sda_update_cfg)
> +						 * (t_calc->div_low) + 1)
> +						 * 1000000, clk_rate_khz);
> +		if ((max_hold_data_ns < spec->max_data_hold_ns) &&
> +		    (min_setup_data_ns > spec->min_data_setup_ns))
> +			break;
> +	}
> +
> +	/* calculate setup start config */
> +	min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns;
> +	stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns
> +			   - 1000000, 8 * 1000000 * (t_calc->div_high));
> +
> +	/* calculate setup stop config */
> +	min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns;
> +	stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns
> +			   - 1000000, 8 * 1000000 * (t_calc->div_high));
> +
> +	t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) |
> +			 REG_CON_STA_CFG(--stp_sta_cfg) |
> +			 REG_CON_STO_CFG(--stp_sto_cfg);
> +
> +	t_calc->div_low--;
> +	t_calc->div_high--;
> +
> +	/* Maximum divider supported by hw is 0xffff */
> +	if (t_calc->div_low > 0xffff) {
> +		t_calc->div_low = 0xffff;
> +		ret = -EINVAL;
> +	}
> +
> +	if (t_calc->div_high > 0xffff) {
> +		t_calc->div_high = 0xffff;
> +		ret = -EINVAL;
> +	}
> +
> +	return ret;
> +}
> +
>   static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
>   {
>   	struct i2c_timings *t = &i2c->t;
>   	struct rk3x_i2c_calced_timings calc;
>   	u64 t_low_ns, t_high_ns;
> +	u32 val;
>   	int ret;
>   
> -	ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
> +	ret = i2c->soc_data->calc_timings(clk_rate, t, &calc);
>   	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
>   
> -	clk_enable(i2c->clk);
> +	clk_enable(i2c->pclk);
> +
>   	i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
>   		   REG_CLKDIV);
> -	clk_disable(i2c->clk);
> +
> +	val = i2c_readl(i2c, REG_CON);
> +	val &= ~REG_CON_TUNING_MASK;
> +	val |= calc.tuning;
> +	i2c_writel(i2c, val, REG_CON);
> +
> +	clk_disable(i2c->pclk);
>   
>   	t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
>   	t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
> @@ -712,7 +914,13 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
>   
>   	switch (event) {
>   	case PRE_RATE_CHANGE:
> -		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0)
> +		/*
> +		 * Try the calculation (but don't store the result) ahead of
> +		 * time to see if we need to block the clock change.  Timings
> +		 * shouldn't actually take effect until rk3x_i2c_adapt_div().
> +		 */
> +		if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t,
> +						&calc) != 0)
>   			return NOTIFY_STOP;
>   
>   		/* scale up */
> @@ -822,12 +1030,14 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
>   {
>   	struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
>   	unsigned long timeout, flags;
> +	u32 val;
>   	int ret = 0;
>   	int i;
>   
>   	spin_lock_irqsave(&i2c->lock, flags);
>   
>   	clk_enable(i2c->clk);
> +	clk_enable(i2c->pclk);
>   
>   	i2c->is_last_msg = false;
>   
> @@ -861,7 +1071,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
>   
>   			/* Force a STOP condition without interrupt */
>   			i2c_writel(i2c, 0, REG_IEN);
> -			i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON);
> +			val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
> +			val |= REG_CON_EN | REG_CON_STOP;
> +			i2c_writel(i2c, val, REG_CON);
>   
>   			i2c->state = STATE_IDLE;
>   
> @@ -875,7 +1087,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
>   		}
>   	}
>   
> +	clk_disable(i2c->pclk);
>   	clk_disable(i2c->clk);
> +
>   	spin_unlock_irqrestore(&i2c->lock, flags);
>   
>   	return ret < 0 ? ret : num;
> @@ -893,18 +1107,27 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
>   
>   static const struct rk3x_i2c_soc_data rk3066_soc_data = {
>   	.grf_offset = 0x154,
> +	.calc_timings = rk3x_i2c_v0_calc_timings,
>   };
>   
>   static const struct rk3x_i2c_soc_data rk3188_soc_data = {
>   	.grf_offset = 0x0a4,
> +	.calc_timings = rk3x_i2c_v0_calc_timings,
>   };
>   
>   static const struct rk3x_i2c_soc_data rk3228_soc_data = {
>   	.grf_offset = -1,
> +	.calc_timings = rk3x_i2c_v0_calc_timings,
>   };
>   
>   static const struct rk3x_i2c_soc_data rk3288_soc_data = {
>   	.grf_offset = -1,
> +	.calc_timings = rk3x_i2c_v0_calc_timings,
> +};
> +
> +static const struct rk3x_i2c_soc_data rk3399_soc_data = {
> +	.grf_offset = -1,
> +	.calc_timings = rk3x_i2c_v1_calc_timings,
>   };
>   
>   static const struct of_device_id rk3x_i2c_match[] = {
> @@ -924,6 +1147,10 @@ static const struct of_device_id rk3x_i2c_match[] = {
>   		.compatible = "rockchip,rk3288-i2c",
>   		.data = (void *)&rk3288_soc_data
>   	},
> +	{
> +		.compatible = "rockchip,rk3399-i2c",
> +		.data = (void *)&rk3399_soc_data
> +	},
>   	{},
>   };
>   MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
> @@ -963,12 +1190,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
>   	spin_lock_init(&i2c->lock);
>   	init_waitqueue_head(&i2c->wait);
>   
> -	i2c->clk = devm_clk_get(&pdev->dev, NULL);
> -	if (IS_ERR(i2c->clk)) {
> -		dev_err(&pdev->dev, "cannot get clock\n");
> -		return PTR_ERR(i2c->clk);
> -	}
> -
>   	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>   	i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
>   	if (IS_ERR(i2c->regs))
> @@ -1022,17 +1243,44 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
>   
>   	platform_set_drvdata(pdev, i2c);
>   
> +	if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) {
> +		/* Only one clock to use for bus clock and peripheral clock */
> +		i2c->clk = devm_clk_get(&pdev->dev, NULL);
> +		i2c->pclk = i2c->clk;
> +	} else {
> +		i2c->clk = devm_clk_get(&pdev->dev, "i2c");
> +		i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
> +	}
> +
> +	if (IS_ERR(i2c->clk)) {
> +		ret = PTR_ERR(i2c->clk);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret);
> +		return ret;
> +	}
> +	if (IS_ERR(i2c->pclk)) {
> +		ret = PTR_ERR(i2c->pclk);
> +		if (ret != -EPROBE_DEFER)
> +			dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret);
> +		return ret;
> +	}
> +
>   	ret = clk_prepare(i2c->clk);
>   	if (ret < 0) {
> -		dev_err(&pdev->dev, "Could not prepare clock\n");
> +		dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret);
>   		return ret;
>   	}
> +	ret = clk_prepare(i2c->pclk);
> +	if (ret < 0) {
> +		dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret);
> +		goto err_clk;
> +	}
>   
>   	i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
>   	ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb);
>   	if (ret != 0) {
>   		dev_err(&pdev->dev, "Unable to register clock notifier\n");
> -		goto err_clk;
> +		goto err_pclk;
>   	}
>   
>   	clk_rate = clk_get_rate(i2c->clk);
> @@ -1050,6 +1298,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
>   
>   err_clk_notifier:
>   	clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
> +err_pclk:
> +	clk_unprepare(i2c->pclk);
>   err_clk:
>   	clk_unprepare(i2c->clk);
>   	return ret;
> @@ -1062,6 +1312,7 @@ static int rk3x_i2c_remove(struct platform_device *pdev)
>   	i2c_del_adapter(&i2c->adap);
>   
>   	clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
> +	clk_unprepare(i2c->pclk);
>   	clk_unprepare(i2c->clk);
>   
>   	return 0;


-- 
Thanks,
Caesar



From caesar.upstream at gmail.com  Wed May 11 04:44:58 2016
From: caesar.upstream at gmail.com (Caesar Wang)
Date: Wed, 11 May 2016 19:44:58 +0800
Subject: [PATCH v8 8/8] i2c: rk3x: support fast-mode plus for rk3399
In-Reply-To: <1462908794-27333-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908794-27333-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <57331B3A.7050801@gmail.com>



? 2016?05?11? 03:33, David Wu ??:
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>

Tested-by: Caesar Wang <wxt at rock-chips.com>
> ---
> Change in v8:
> - None
>
>   drivers/i2c/busses/i2c-rk3x.c | 21 +++++++++++++++++----
>   1 file changed, 17 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
> index 25ed1ad..0ba25ee 100644
> --- a/drivers/i2c/busses/i2c-rk3x.c
> +++ b/drivers/i2c/busses/i2c-rk3x.c
> @@ -126,6 +126,17 @@ static const struct i2c_spec_values fast_mode_spec = {
>   	.min_hold_buffer_ns = 1300,
>   };
>   
> +static const struct i2c_spec_values fast_mode_plus_spec = {
> +	.min_hold_start_ns = 260,
> +	.min_low_ns = 500,
> +	.min_high_ns = 260,
> +	.min_setup_start_ns = 260,
> +	.max_data_hold_ns = 400,
> +	.min_data_setup_ns = 50,
> +	.min_setup_stop_ns = 260,
> +	.min_hold_buffer_ns = 500,
> +};
> +
>   /**
>    * struct rk3x_i2c_calced_timings:
>    * @div_low: Divider output for low
> @@ -531,8 +542,10 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
>   {
>   	if (speed <= 100000)
>   		return &standard_mode_spec;
> -	else
> +	else if (speed <= 400000)
>   		return &fast_mode_spec;
> +	else
> +		return &fast_mode_plus_spec;
>   }
>   
>   /**
> @@ -743,9 +756,9 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
>   	const struct i2c_spec_values *spec;
>   	int ret = 0;
>   
> -	/* Support standard-mode and fast-mode */
> -	if (WARN_ON(t->bus_freq_hz > 400000))
> -		t->bus_freq_hz = 400000;
> +	/* Support standard-mode, fast-mode and fast-mode plus */
> +	if (WARN_ON(t->bus_freq_hz > 1000000))
> +		t->bus_freq_hz = 1000000;
>   
>   	/* prevent scl_rate_khz from becoming 0 */
>   	if (WARN_ON(t->bus_freq_hz < 1000))


-- 
Thanks,
Caesar



From heiko at sntech.de  Wed May 11 05:42:23 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Wed, 11 May 2016 14:42:23 +0200
Subject: [PATCH] mmc: dw_mmc: rockchip: Set the drive phase to 180 degrees
In-Reply-To: <1462904195-18229-1-git-send-email-dianders@chromium.org>
References: <1462904195-18229-1-git-send-email-dianders@chromium.org>
Message-ID: <6174748.3ugS9uJXKS@phil>

Am Dienstag, 10. Mai 2016, 11:16:35 schrieb Douglas Anderson:
> Historically for Rockchip devices we've relied on the power-on
> default (or perhaps the firmware setting) to get the correct drive
> phase for dw_mmc devices.  This worked OK for the most part, but:
> 
> * Relying on the setting just "being right" is a bit fragile.
> 
> * As soon as there is an instance where the power on default is wrong or
>   where the firmware didn't configure this properly then we'll get a
>   mysterious failure.
> 
> Let's explicitly set this phase in the kernel.
> 
> You might notice that this patch is currently very dumb and just always
> sets this phase to 180 degrees.  As far as I can tell this is actually a
> sane thing to do.  From reading through the Designware Databook it
> appears that there are instances where you could still meet hold time
> requirements and set this phase to 90 degrees, but nothing I've read
> indicates that 180 degrees is not OK also.
> 
> As indicated above, adding a delay to the drive is used to achieve
> proper hold times.  For a given speed mode hold times are listed in the
> spec in terms of nanoseconds.  The hold times are different for
> different speed modes.  The actual hold time achieved is actually a
> function of Delay_O (an internal delay in dw_mmc, which could vary from
> SoC model to SoC model), pad delays, and the drive delay (which we're
> setting here).  Note also that by setting the drive delay as a phase we
> will get a different number of nanoseconds of delay depending on the
> input clock.
> 
> Note that, as far as I can tell, this _does_ change the behavior of
> rk3288 devices.  On devices I tested, which use coreboot/depthcharge as
> BIOS, the SDMMC/SDIO0/SDIO1 drive phase used to be 90 degrees.  Now it
> will be 180 degrees.  With my understanding from the Designware Databook
> the 180 degrees ought to be more correct and should increase
> compatibility.
> 
> I have tested this by inserting my collection of uSD cards (mostly UHS,
> though a few not) into a veyron_minnie and confirmed that they still
> seem to enumerate properly.  For a subset of them I tried putting a
> filesystem on them and also tried running mmc_test.
> 
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> ---
>  drivers/mmc/host/dw_mmc-rockchip.c | 21 +++++++++++++++++++++
>  1 file changed, 21 insertions(+)
> 
> diff --git a/drivers/mmc/host/dw_mmc-rockchip.c
> b/drivers/mmc/host/dw_mmc-rockchip.c index 8c20b81cafd8..62cbd33a07cd
> 100644
> --- a/drivers/mmc/host/dw_mmc-rockchip.c
> +++ b/drivers/mmc/host/dw_mmc-rockchip.c
> @@ -66,6 +66,27 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host,
> struct mmc_ios *ios) /* Make sure we use phases which we can enumerate
> with */
>  	if (!IS_ERR(priv->sample_clk))
>  		clk_set_phase(priv->sample_clk, priv->default_sample_phase);
> +
> +	/*
> +	 * Set the drive phase to 180 degrees.  This helps us achieve proper
> +	 * hold times.
> +	 *
> +	 * Note that this is _not_ a value that is tuned and is also _not_ a
> +	 * value that will vary from board to board.  It is a value that
> +	 * _could_ vary between different SoC models (could be different on
> +	 * rk3066 vs. rk3288 for instance).  It is also a value that _could_

I saw you talking with Shawn in the other thread on doing this in a 
different way, but that statement itself is incorrect and should not land in 
the kernel.

At least rk3066/rk3188 (and most likely earlier) do not support the tuning 
at all and the drive-clock is going through a static non-controllable 
inverter (according to the CRU docs), so should always be at 180 degrees.


> +	 * need to be adjusted based on our clock frequency and speed mode
> +	 * since different speed modes have different hold time requirements
> +	 * and hold time requirements are in "ns" (a phase offset adds a
> +	 * different "ns" delay for different input clocks).
> +	 *
> +	 * Despite these theoretical needs, it has been observed that 180
> +	 * degrees gives us good signaling across all tested SoCs and all
> +	 * tested speed modes.  If when we find someone that needs 90 degrees
> +	 * here we can add a table based on speed mode / SoC compatible ID.
> +	 */
> +	if (!IS_ERR(priv->drv_clk))
> +		clk_set_phase(priv->drv_clk, 180);
>  }
> 
>  #define NUM_PHASES			360



From heiko at sntech.de  Wed May 11 07:51:58 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Wed, 11 May 2016 16:51:58 +0200
Subject: [PATCH 2/2] ARM64: dts: rockchip: enable eMMC for rk3399 EVB
In-Reply-To: <1462924975-69072-2-git-send-email-briannorris@chromium.org>
References: <1462924975-69072-1-git-send-email-briannorris@chromium.org>
 <1462924975-69072-2-git-send-email-briannorris@chromium.org>
Message-ID: <4355979.JCGxOmTVBW@phil>

Hi Brian,

Am Dienstag, 10. Mai 2016, 17:02:55 schrieb Brian Norris:
> The 'mmc-hs400-enhanced-strobe' property has been acked by Rob Herring,
> though it's still not merged.

The commit message should describe the actual change not the volatile 
environment surrounding it :-) .

When I apply this patch the property-binding will have made it into a 
maintainer-tree so is not valid anymore then. That is more material for the 
"comment-section" below the "---"

> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
>  arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts index
> 1a3eb1482050..ccfd2bcf02e1 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> @@ -89,6 +89,18 @@
>  	status = "okay";
>  };
> 
> +&emmc_phy {
> +	status = "okay";
> +};
> +
> +&sdhci {
> +	bus-width = <8>;
> +	mmc-hs400-1_8v;
> +	non-removable;
> +	mmc-hs400-enhanced-strobe;

alphabetic ordering of properties please

> +	status = "okay";
> +};
> +
>  &uart2 {
>  	status = "okay";
>  };



From heiko at sntech.de  Wed May 11 08:04:49 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Wed, 11 May 2016 17:04:49 +0200
Subject: [PATCH v8 1/8] i2c: rk3x: add documentation to fields in "struct
 rk3x_i2c"
In-Reply-To: <1462908252-27016-2-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908252-27016-2-git-send-email-david.wu@rock-chips.com>
Message-ID: <4217955.sKb92Wcadr@phil>

Am Mittwoch, 11. Mai 2016, 03:24:05 schrieb David Wu:

In general, all patches should have a commit message (even if it's obvious) 
and some maintainers even enforce this in a hard way.

How about something like:

----
Add kernel-doc documentation for the elements of the previously
undocumented struct rk3x_i2c.
----

Some minor nitpicks below, otherwise
Reviewed-by: Heiko Stuebner <heiko at sntech.de>

> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>
> ---
> Change in v8:
> - none
> 
>  drivers/i2c/busses/i2c-rk3x.c | 22 +++++++++++++++++++++-
>  1 file changed, 21 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
> index 80bed02..7e45d51 100644
> --- a/drivers/i2c/busses/i2c-rk3x.c
> +++ b/drivers/i2c/busses/i2c-rk3x.c
> @@ -90,6 +90,26 @@ struct rk3x_i2c_soc_data {
>  	int grf_offset;
>  };
> 
> +/**
> + * struct rk3x_i2c - private data of the controller
> + * @adap: corresponding I2C adapter
> + * @dev: device for this controller
> + * @soc_data: related soc data struct
> + * @regs: virtual memory area
> + * @clk: clock of i2c bus
> + * @clk_rate_nb: i2c clk rate change notify
		^ i2c clk rate change notifier block

> + * @t: I2C known timing information
> + * @lock: spinlock for the i2c bus
> + * @wait: the waitqueue to wait for i2c transfer
> + * @busy: the condition for the event to wait for
> + * @msg: current i2c message
> + * @addr: addr of i2c slave device
> + * @mode: mode of i2c transfer
> + * @is_last_msg: flag determines whether it is the last msg in this
> transfer + * @state: state of i2c transfer
> + * @processed: byte length which has been send or received
										^ sent (with a "t")

> + * @error: error code for i2c transfer
> + */
>  struct rk3x_i2c {
>  	struct i2c_adapter adap;
>  	struct device *dev;
> @@ -116,7 +136,7 @@ struct rk3x_i2c {
> 
>  	/* I2C state machine */
>  	enum rk3x_i2c_state state;
> -	unsigned int processed; /* sent/received bytes */
> +	unsigned int processed;
>  	int error;
>  };



From dianders at chromium.org  Wed May 11 09:35:29 2016
From: dianders at chromium.org (Doug Anderson)
Date: Wed, 11 May 2016 09:35:29 -0700
Subject: [PATCH v8 6/8] dt-bindings: i2c: rk3x: add support for rk3399
In-Reply-To: <1462908647-27236-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908647-27236-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=VzL8AfzUnPYgsf_NqPgbp2_o_qJC7-DWHmekWVQ-Es=A@mail.gmail.com>

Hi,

On Tue, May 10, 2016 at 12:30 PM, David Wu <david.wu at rock-chips.com> wrote:
> The bus clock and function clock are separated at rk3399,
> and others use one clock as the bus clock and function clock.
>
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>
> ---
> Change in v8:
> - remove error description.
>
>  Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 16 +++++++++++++---
>  1 file changed, 13 insertions(+), 3 deletions(-)
>
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> index 0b4a85f..5429301 100644
> --- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> +++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> @@ -6,10 +6,20 @@ RK3xxx SoCs.
>  Required properties :
>
>   - reg : Offset and length of the register set for the device
> - - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c",
> -               "rockchip,rk3228-i2c" or "rockchip,rk3288-i2c".
> + - compatible: should be one of the following:
> +   - "rockchip,rk3066-i2c": for rk3066
> +   - "rockchip,rk3188-i2c": for rk3188
> +   - "rockchip,rk3228-i2c": for rk3228
> +   - "rockchip,rk3288-i2c": for rk3288
> +   - "rockchip,rk3399-i2c": for rk3399
>   - interrupts : interrupt number
> - - clocks : parent clock
> + - clocks: See ../clock/clock-bindings.txt
> +   - For older hardware (rk3066, rk3188, rk3228, rk3288):
> +     - There is one clock that's used both to derive the functional clock
> +       for the device and as the bus clock.
> +   - For newer hardware (rk3399): specified by name
> +     - "i2c": REQUIRED. This is used to derive the functional clock.
> +     - "pclk": REQUIRED. This is the bus clock.

Depending on what Rob thinks, it might make sense to remove the above
two "REQUIRED" bits.  That would match his earlier feedback since
we're still in the "Required" section and thus it is redundant.

-Doug


From dianders at chromium.org  Wed May 11 10:37:57 2016
From: dianders at chromium.org (Doug Anderson)
Date: Wed, 11 May 2016 10:37:57 -0700
Subject: [PATCH v8 7/8] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <1462908698-27284-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908698-27284-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=Uf-U3RBpgFbR3LkPAJTWqz3d02+H7iyA-SS-y=r3cXjA@mail.gmail.com>

Hi,

On Tue, May 10, 2016 at 12:31 PM, David Wu <david.wu at rock-chips.com> wrote:
>  static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
>  {
>         struct i2c_timings *t = &i2c->t;
>         struct rk3x_i2c_calced_timings calc;
>         u64 t_low_ns, t_high_ns;
> +       u32 val;
>         int ret;
>
> -       ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
> +       ret = i2c->soc_data->calc_timings(clk_rate, t, &calc);
>         WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
>
> -       clk_enable(i2c->clk);
> +       clk_enable(i2c->pclk);
> +
>         i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
>                    REG_CLKDIV);
> -       clk_disable(i2c->clk);
> +
> +       val = i2c_readl(i2c, REG_CON);
> +       val &= ~REG_CON_TUNING_MASK;
> +       val |= calc.tuning;
> +       i2c_writel(i2c, val, REG_CON);

Another subtle bug here.  You need to be holding the spinlock here
since you're doing a read-modify-write of a register that is also
touched by the interrupt handler.  We never needed it before because
the previous register update wasn't touched by anyone else and it was
a single atomic write.

Also: technically if we are midway through a transfer when all this
happens then there will be a very short period of time when the two
timing-related registers won't match with each other.  I have no idea
how much that would matter, but in the very least it seems wise to
minimize the time where they mismatch.  So I'd probably write:

       spin_lock_irqsave(&i2c->lock, flags);
       val = i2c_readl(i2c, REG_CON);
       val &= ~REG_CON_TUNING_MASK;
       val |= calc.tuning;
       i2c_writel(i2c, val, REG_CON);
       i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
                  REG_CLKDIV);
       spin_unlock_irqrestore(&i2c->lock, flags);

...if we really end up with on a system with a dynamically changing
clock that uses the new-style timing and we see real problems, we can
always try to come up with a way to avoid any problems.  Sound OK?


Otherwise, I think things look good to me.  Caesar's comments would
also be good to fix.


-Doug


From heiko at sntech.de  Wed May 11 11:20:56 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Wed, 11 May 2016 20:20:56 +0200
Subject: [PATCH v8 6/8] dt-bindings: i2c: rk3x: add support for rk3399
In-Reply-To: <1462908647-27236-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908647-27236-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1949934.3LNZYXcpHY@phil>

Am Mittwoch, 11. Mai 2016, 03:30:47 schrieb David Wu:
> The bus clock and function clock are separated at rk3399,
> and others use one clock as the bus clock and function clock.
> 
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>

I'd second what Doug said wrt. the removal of the unnecessary "REQUIRED" 
statements of the clock names, especially as the surrounding text makes that 
requirement pretty clear.

Otherwiese looks nice, so

Reviewed-by: Heiko Stuebner <heiko at sntech.de>

> ---
> Change in v8:
> - remove error description.
> 
>  Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 16 +++++++++++++---
>  1 file changed, 13 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt index
> 0b4a85f..5429301 100644
> --- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> +++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
> @@ -6,10 +6,20 @@ RK3xxx SoCs.
>  Required properties :
> 
>   - reg : Offset and length of the register set for the device
> - - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c",
> -		"rockchip,rk3228-i2c" or "rockchip,rk3288-i2c".
> + - compatible: should be one of the following:
> +   - "rockchip,rk3066-i2c": for rk3066
> +   - "rockchip,rk3188-i2c": for rk3188
> +   - "rockchip,rk3228-i2c": for rk3228
> +   - "rockchip,rk3288-i2c": for rk3288
> +   - "rockchip,rk3399-i2c": for rk3399
>   - interrupts : interrupt number
> - - clocks : parent clock
> + - clocks: See ../clock/clock-bindings.txt
> +   - For older hardware (rk3066, rk3188, rk3228, rk3288):
> +     - There is one clock that's used both to derive the functional clock
> +       for the device and as the bus clock.
> +   - For newer hardware (rk3399): specified by name
> +     - "i2c": REQUIRED. This is used to derive the functional clock.
> +     - "pclk": REQUIRED. This is the bus clock.
> 
>  Required on RK3066, RK3188 :



From heiko at sntech.de  Wed May 11 11:26:52 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Wed, 11 May 2016 20:26:52 +0200
Subject: [PATCH v8 3/8] i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
In-Reply-To: <1462908252-27016-4-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908252-27016-4-git-send-email-david.wu@rock-chips.com>
Message-ID: <2477327.hJjg0APDhg@phil>

Am Mittwoch, 11. Mai 2016, 03:24:07 schrieb David Wu:
> Call rk3x_i2c_setup() before rk3x_i2c_start()

That beginning of the sentence could use a tiny improvement, like

----
rk3x_i2c_setup() gets called directly before rk3x_i2c_start()
----

to make it obvious what happens in the code.

But a nice small improvement
Reviewed-by: Heiko Stuebner <heiko at sntech.de>

> and the last thing in setup was to clean the IPD,
> so no reason to do it at the beginning of start.
> 
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>
> ---
> Change in v8:
> - none
> 
>  drivers/i2c/busses/i2c-rk3x.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
> index 1e2677a..9eeb4e5 100644
> --- a/drivers/i2c/busses/i2c-rk3x.c
> +++ b/drivers/i2c/busses/i2c-rk3x.c
> @@ -174,7 +174,6 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c)
>  {
>  	u32 val;
> 
> -	rk3x_i2c_clean_ipd(i2c);
>  	i2c_writel(i2c, REG_INT_START, REG_IEN);
> 
>  	/* enable adapter with correct mode, send START condition */



From heiko at sntech.de  Wed May 11 14:09:43 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Wed, 11 May 2016 23:09:43 +0200
Subject: [PATCH v8 8/8] i2c: rk3x: support fast-mode plus for rk3399
In-Reply-To: <1462908794-27333-1-git-send-email-david.wu@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908794-27333-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <5153288.jNhUuzGC3g@phil>

Am Mittwoch, 11. Mai 2016, 03:33:14 schrieb David Wu:

please always try to also provide some sort of commit message.

---
Implement fast mode plus that allows bus speeds of up to 1MHz.
.....

---

Additionally, the i2c-noob in me would wish for a short sentence on where 
the timing values come from (measured, somewhere in the TRM I didn't find or 
something completely different).


Patch content itself looks good, so with a suitable commit message,
Reviewed-by: Heiko Stuebner <heiko at sntech.de>


> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>
> ---
> Change in v8:
> - None
> 
>  drivers/i2c/busses/i2c-rk3x.c | 21 +++++++++++++++++----
>  1 file changed, 17 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
> index 25ed1ad..0ba25ee 100644
> --- a/drivers/i2c/busses/i2c-rk3x.c
> +++ b/drivers/i2c/busses/i2c-rk3x.c
> @@ -126,6 +126,17 @@ static const struct i2c_spec_values fast_mode_spec =
> { .min_hold_buffer_ns = 1300,
>  };
> 
> +static const struct i2c_spec_values fast_mode_plus_spec = {
> +	.min_hold_start_ns = 260,
> +	.min_low_ns = 500,
> +	.min_high_ns = 260,
> +	.min_setup_start_ns = 260,
> +	.max_data_hold_ns = 400,
> +	.min_data_setup_ns = 50,
> +	.min_setup_stop_ns = 260,
> +	.min_hold_buffer_ns = 500,
> +};
> +
>  /**
>   * struct rk3x_i2c_calced_timings:
>   * @div_low: Divider output for low
> @@ -531,8 +542,10 @@ static const struct i2c_spec_values
> *rk3x_i2c_get_spec(unsigned int speed) {
>  	if (speed <= 100000)
>  		return &standard_mode_spec;
> -	else
> +	else if (speed <= 400000)
>  		return &fast_mode_spec;
> +	else
> +		return &fast_mode_plus_spec;
>  }
> 
>  /**
> @@ -743,9 +756,9 @@ static int rk3x_i2c_v1_calc_timings(unsigned long
> clk_rate, const struct i2c_spec_values *spec;
>  	int ret = 0;
> 
> -	/* Support standard-mode and fast-mode */
> -	if (WARN_ON(t->bus_freq_hz > 400000))
> -		t->bus_freq_hz = 400000;
> +	/* Support standard-mode, fast-mode and fast-mode plus */
> +	if (WARN_ON(t->bus_freq_hz > 1000000))
> +		t->bus_freq_hz = 1000000;
> 
>  	/* prevent scl_rate_khz from becoming 0 */
>  	if (WARN_ON(t->bus_freq_hz < 1000))



From dianders at chromium.org  Wed May 11 14:40:48 2016
From: dianders at chromium.org (Douglas Anderson)
Date: Wed, 11 May 2016 14:40:48 -0700
Subject: [PATCH v2] mmc: dw_mmc: rockchip: Set the drive phase properly
Message-ID: <1463002848-580-1-git-send-email-dianders@chromium.org>

Historically for Rockchip devices we've relied on the power-on
default (or perhaps the firmware setting) to get the correct drive
phase for dw_mmc devices.  This worked OK for the most part, but:

* Relying on the setting just "being right" is a bit fragile.

* As soon as there is an instance where the power on default is wrong or
  where the firmware didn't configure this properly then we'll get a
  mysterious failure.

Let's explicitly set this phase in the kernel.

The comments inside this patch try to explain the situation quite
throughly, but the high level overview of this is:

Before this patch on rk3288 devices tested:
* eMMC: 180 degrees
* SDMMC/SDIO0/SDIO1: 90 degrees

After this patch:
* Use 90 degree phase offset usually.
* Use 180 degree phase offset for MMC_DDR52, SDR104, HS200.

That means we are _changing_ behavior for those devices in this way:

* If we have HS200 eMMC or DDR52 eMMC, we'll run ID mode at 90
  degrees (vs 180) but otherwise have no change.

* For any non-HS200 / non-DDR52 eMMC devices we'll now _always_ run at
  90 degrees (vs 180).  It seems fairly unlikely that building modern
  hardware is using an eMMC that isn't using DDR52 or HS200, of course.

* For SDR104 cards we'll now run with 180 degree phase offset (vs 90).
  It's expected that 90 degree phase offset would have worked OK, but
  this gives us extra margin.

I have tested this by inserting my collection of uSD cards (mostly UHS,
though a few not) into a veyron_minnie and confirmed that they still
seem to enumerate properly.  For a subset of them I tried putting a
filesystem on them and also tried running mmc_test.

Signed-off-by: Douglas Anderson <dianders at chromium.org>
---
Changes in v2:
- Now use 90 degrees for some modes; updated comments to say why.

 drivers/mmc/host/dw_mmc-rockchip.c | 64 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 8c20b81cafd8..8068fa887db8 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -66,6 +66,70 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 	/* Make sure we use phases which we can enumerate with */
 	if (!IS_ERR(priv->sample_clk))
 		clk_set_phase(priv->sample_clk, priv->default_sample_phase);
+
+	/*
+	 * Set the drive phase offset based on speed mode to achieve hold times.
+	 *
+	 * That this is _not_ a value that is dynamically tuned and is also
+	 * _not_ a value that will vary from board to board.  It is a value
+	 * that could vary between different SoC models if they had massively
+	 * different output clock delays inside their dw_mmc IP block (delay_o),
+	 * but since it's OK to overshoot a little we don't need to do complex
+	 * calculations and can pick values that will just work for everyone.
+	 *
+	 * When picking values we'll stick with picking 0/90/180/270 since
+	 * those can be made very accurately on all known Rockchip SoCs.
+	 *
+	 * Note that these values match values from the DesignWare Databook
+	 * tables for the most part except for SDR12 and "ID mode".  For those
+	 * two modes the databook calculations assume a clock in of 50MHz.  As
+	 * seen above, we always use a clock in rate that is exactly the
+	 * card's input clock (times RK3288_CLKGEN_DIV, but that gets divided
+	 * back out before the controller sees it).
+	 *
+	 * From measurement of a single device, it appears that delay_o is
+	 * about .5 ns.  Since we try to leave a bit of margin, it's expected
+	 * that numbers here will be fine even with much larger delay_o
+	 * (the 1.4 ns assumed by the DesignWare Databook would result in the
+	 * same results, for instance).
+	 */
+	if (!IS_ERR(priv->drv_clk)) {
+		int phase;
+
+		/*
+		 * In almost all cases a 90 degree phase offset will provide
+		 * sufficient hold times across all valid input clock rates
+		 * assuming delay_o is not absurd for a given SoC.  We'll use
+		 * that as a default.
+		 */
+		phase = 90;
+
+		switch (ios->timing) {
+		case MMC_TIMING_MMC_DDR52:
+			/*
+			 * Since clock in rate with MMC_DDR52 is doubled when
+			 * bus width is 8 we need to double the phase offset
+			 * to get the same timings.
+			 */
+			if (ios->bus_width == MMC_BUS_WIDTH_8)
+				phase = 180;
+			break;
+		case MMC_TIMING_UHS_SDR104:
+		case MMC_TIMING_MMC_HS200:
+			/*
+			 * In the case of 150 MHz clock (typical max for
+			 * Rockchip SoCs), 90 degree offset will add a delay
+			 * of 1.67 ns.  That will meet min hold time of .8 ns
+			 * as long as clock output delay is < .87 ns.  On
+			 * SoCs measured this seems to be OK, but it doesn't
+			 * hurt to give margin here, so we use 180.
+			 */
+			phase = 180;
+			break;
+		}
+
+		clk_set_phase(priv->drv_clk, phase);
+	}
 }
 
 #define NUM_PHASES			360
-- 
2.8.0.rc3.226.g39d4020



From dianders at chromium.org  Wed May 11 14:42:40 2016
From: dianders at chromium.org (Doug Anderson)
Date: Wed, 11 May 2016 14:42:40 -0700
Subject: [PATCH 2/2] dt-bindings: rockchip-dw-mshc: add rockchip,
 default-drv-phase
In-Reply-To: <2994d365-2cf2-0990-6c10-2abeebb42eef@rock-chips.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
 <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=WSkBwBjVsRoDsfjD+sNfR70mKGRA0khjPKKW0zS2=PTw@mail.gmail.com>
 <b15dcb4f-1584-8219-2fe0-97eecb0c64a6@rock-chips.com>
 <CAD=FV=XToSzqSh=SShHuQU9W_m7gfyQn8wRXkLy79t+tnqZknA@mail.gmail.com>
 <1f2f43c7-2672-e448-eddb-2d613bb8dc48@rock-chips.com>
 <CAD=FV=UGbrJRyUbbgzbcYf9GjPG+Fh_gpQ3rX2G=wi2w5Lw=Sg@mail.gmail.com>
 <e202f663-88d7-693b-a765-c130e68d1c2d@rock-chips.com>
 <CAD=FV=UyYCqMYKScjVEASrbzO75014kPCEt39uOSTsgq9M==YQ@mail.gmail.com>
 <2994d365-2cf2-0990-6c10-2abeebb42eef@rock-chips.com>
Message-ID: <CAD=FV=V1dOsZkcFCd50N7F5qCVFMn789n3Hsopd7MDmdupim3Q@mail.gmail.com>

Shawn,

On Wed, May 11, 2016 at 1:25 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> On 2016/5/11 11:50, Doug Anderson wrote:
>>
>> Hi,
>>
>> On Tue, May 10, 2016 at 7:50 PM, Shawn Lin <shawn.lin at rock-chips.com>
>> wrote:
>>>>>
>>>>> maybe. But I think 180(downside) is the better.
>>>
>>>
>>>
>>> NAK my previous comments here. Downside is better for SRD, but won't
>>> work for DDR mode. When running in DDR mode, we should use 90 instead.
>>>
>>> So let me elaborate a bit more here.
>>> For DDR mode, one single clk cycle should sending two data bits outside
>>> to the devices. We need a hold time for both. If 180 is used, the first
>>> bit occurs around the downside area, which won't be sampled by devices
>>> on the upside.  So on the upside, the devices will see a zero bit if you
>>> actually send a one-bit, which makes the devices  generate CRC finally.
>>>
>>>
>>> For this above, 180 for all SDR mode is ok, but 90 should be deployed
>>> for DDR mode. So simply checking the timing to hardcode it should be
>>> fine.
>>
>>
>> OK, I sent out a patch for 180 always.  I can send v2 to use 90 for
>> DDR modes tomorrow.  ...or feel free to post that yourself if you
>> want.
>>
>> We want 90 for all DDR modes?  So MMC_TIMING_UHS_DDR50,
>> MMC_TIMING_MMC_DDR52, MMC_TIMING_MMC_HS400? (not that we support HS400
>> in dw_mmc on Rockchip).
>
>
> Right.

OK, so I dug into this more.  I don't think it's actually quite that
simple.  The Designware databook explicitly states that 'MMC DDR
8-bit' should use 180, not 90.  ...but that's probably explained by
the fact that "cclk_in" for MMC-DDR 8-bit is double what you'd expect.
You can see that in code:

if (ios->bus_width == MMC_BUS_WIDTH_8 &&
    ios->timing == MMC_TIMING_MMC_DDR52)
      cclkin = 2 * ios->clock * RK3288_CLKGEN_DIV;

---

tl;dr of all the below:

* For SD: use 180 for SDR104 to get margin, use 90 elsewhere.
* For mmc, use 180 for DDR52 to meet timings, use 180 for HS200 to get
margin, use 90 elsewhere


The nice thing about this is, at least for rk3288, things don't change
much from today where we use 90 degrees for most SD cards.

---

For new patch, see: <https://patchwork.kernel.org/patch/9075141/>

---

Details:

So assuming measurements I saw from an EE are correct, measured
"delay_o_ns" is ~ .5 ns for rk3399.  With that, we can do some math.
Please correct any mistakes.  Math is hard.  Note that on all Rockchip
devices I've seen pins are limited to 150 MHz and when we choose 150
MHz we end up at 148.5 MHz.  Calculations aren't too different if we
use 150 for that case.


MMC_TIMING_MMC_DDR52:
  min hold time = 2.5 ns
  min data delay = 2.5 ns + .5 ns = 3 ns
  with 100 MHz clock, 90 degree: 2.5 ns
  with 100 MHz clock, 180 degree: 5.0 ns

  ...need 180 degree

--

SD DDR50:
  min hold time = .8 ns
  min data delay = .8 ns + .5 ns = 1.3 ns
  with 50 MHz clock, 90 degree: 5 ns
  with 50 MHz clock, 180 degree: 10 ns

  ...90 degree is good and 180 is massive overkill.  Use 90.

--

SD SDR104 (limited to 148.5 MHz on existing Rockchip parts):
  min hold time = .8 ns
  min data delay = .8 ns + .5 ns = 1.3 ns
  with 148.5 MHz clock, 90 degree: 1.68 ns
  with 148.5 MHz clock, 180 degree: 3.37 ns

  ...so 90 degrees would probably work OK, but 180 degrees gives more margin.
  ...probably explains why existing rk3288 devices w/ 90 degree work OK.

  if we had 200 MHz clock, 90 degree: 1.25 ns
  if we had 200 MHz clock, 180 degree: 2.50 ns

--

SD SDR50:
  min hold time = .8 ns
  min data delay = .8 ns + .5 ns = 1.3 ns
  with 100 MHz clock, 90 degree: 2.5 ns
  with 100 MHz clock, 180 degree: 5.0 ns

  ...90 degree is great w/ plenty of margin

--

SD SDR25:
  min hold time = 2 ns
  min data delay = 2 ns + .5 ns = 2.5 ns
  with 50 MHz clock, 90 degree: 5 ns
  with 50 MHz clock, 180 degree: 10 ns

 ...90 degree is good and 180 is massive overkill.  Use 90.

--

SD SDR12 (databook shows cclk_in as 50 MHz here we'll get 25 MHz):
  min hold time = 5 ns
  min data delay = 5 ns + .5 ns = 5.5 ns
  with 25 MHz clock, 90 degree: 10 ns
  with 25 MHz clock, 180 degree: 20 ns

  ...90 degree is good (databook suggests 180 for this mode due to cclk_in = 50)

--

ID Mode
  min hold time = 5 ns
  min data delay = 5 ns + .5 ns = 5.5 ns
  with 400 kHz clock, 90 degree: 625 ns
  with 400 kHz clock, 180 degree: 1250 ns

  ...90 degree is good  (databook suggests 180 for this mode due to
cclk_in = 50)

--

MMC High speed:
  min hold time = 2.5 ns
  min data delay = 2.5 ns + .5 ns = 3 ns
  with 50 MHz clock, 90 degree: 5 ns
  with 50 MHz clock, 180 degree: 10 ns

  ...90 degree is good

--

HS200:
  min hold time (tIH from JEDEC spec):  .8 ns
  ...math all works out the same as SDR104.

--

HS400:
  we don't support it anyway


From briannorris at chromium.org  Wed May 11 15:31:14 2016
From: briannorris at chromium.org (Brian Norris)
Date: Wed, 11 May 2016 15:31:14 -0700
Subject: [PATCH 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
In-Reply-To: <3e257ce2-056a-592a-9481-970da1fe0627@rock-chips.com>
References: <1462924975-69072-1-git-send-email-briannorris@chromium.org>
 <3e257ce2-056a-592a-9481-970da1fe0627@rock-chips.com>
Message-ID: <20160511223114.GA65449@google.com>

On Wed, May 11, 2016 at 09:17:38AM +0800, Shawn Lin wrote:
> + Huang Lin
> 
> On 2016/5/11 8:02, Brian Norris wrote:
> >The bindings for rk3399's SDHCI + eMMC PHY have been accepted, so let's
> >support eMMC now.
> >
> >Note that 'rockchip,rk3399-sdhci-5.1' is not documented, but per Heiko's
> >previous suggestion, we don't want to clutter the arasan doc, and it's
> >just a precautionary measure to have it.
> >
> >Signed-off-by: Brian Norris <briannorris at chromium.org>
> >---
> > arch/arm64/boot/dts/rockchip/rk3399.dtsi | 23 ++++++++++++++++++++++-
> > 1 file changed, 22 insertions(+), 1 deletion(-)
> >
> >diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> >index 46f325a143b0..947d1221592d 100644
> >--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> >+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> >@@ -215,6 +215,17 @@
> > 		status = "disabled";
> > 	};
> >
> >+	sdhci: sdhci at fe330000 {
> >+		compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
> >+		reg = <0x0 0xfe330000 0x0 0x10000>;
> >+		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
> >+		clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
> 
> sdhci doesn't call clk_set_rate to explicitly assign clk_xin to 200MHz
> as it always assumes sdhci controller should meet the highest speed of
> each timing mode. And the internal divider will be used. So IMHO,
> clk-rockchip for 3399 *haven't* made clk_xin to be 200MHz. Let's assign
> the clk stuff to make sure it's 200MHz.
> 
> Another problem is that emmc_phy contains a configuration which should
> be consistent with clk_out(namely clk_xin/internal dividor). Now I don't
> submit unpstream patchset to expose these configurarion, but in
> prevention of some misleading, I think it's better to to it.
> 
> How about adding these?
> 
> assigned-clocks = <&cru SCLK_EMMC>;
> assigned-clock-parents = <&cru PLL_CPLL>; //may not need
> assigned-clock-rates = <200000000>;

Makes sense. Will add these.

> Still you limit your clk_out by adding max-frequency in dts for
> specific requirment.
> 
> We here manually assigne the clk_xin to be 200MHz, so defaultly
> when it's runing in HS200/HS400(ES) mode, internal divider won't
> be used(by-pass mode). So the clk jitter is better when by-passing the
> clock.
> 
> Thanks.

Brian


From briannorris at chromium.org  Wed May 11 15:32:33 2016
From: briannorris at chromium.org (Brian Norris)
Date: Wed, 11 May 2016 15:32:33 -0700
Subject: [PATCH 2/2] ARM64: dts: rockchip: enable eMMC for rk3399 EVB
In-Reply-To: <4355979.JCGxOmTVBW@phil>
References: <1462924975-69072-1-git-send-email-briannorris@chromium.org>
 <1462924975-69072-2-git-send-email-briannorris@chromium.org>
 <4355979.JCGxOmTVBW@phil>
Message-ID: <20160511223233.GB65449@google.com>

On Wed, May 11, 2016 at 04:51:58PM +0200, Heiko Stuebner wrote:
> Hi Brian,
> 
> Am Dienstag, 10. Mai 2016, 17:02:55 schrieb Brian Norris:
> > The 'mmc-hs400-enhanced-strobe' property has been acked by Rob Herring,
> > though it's still not merged.
> 
> The commit message should describe the actual change not the volatile 
> environment surrounding it :-) .
> 
> When I apply this patch the property-binding will have made it into a 
> maintainer-tree so is not valid anymore then. That is more material for the 
> "comment-section" below the "---"

Of course. I think I just felt guilty without a commit message :)

> > Signed-off-by: Brian Norris <briannorris at chromium.org>
> > ---
> >  arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 12 ++++++++++++
> >  1 file changed, 12 insertions(+)
> > 
> > diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> > b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts index
> > 1a3eb1482050..ccfd2bcf02e1 100644
> > --- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> > +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> > @@ -89,6 +89,18 @@
> >  	status = "okay";
> >  };
> > 
> > +&emmc_phy {
> > +	status = "okay";
> > +};
> > +
> > +&sdhci {
> > +	bus-width = <8>;
> > +	mmc-hs400-1_8v;
> > +	non-removable;
> > +	mmc-hs400-enhanced-strobe;
> 
> alphabetic ordering of properties please

Will fix.

Thanks,
Brian

> > +	status = "okay";
> > +};
> > +
> >  &uart2 {
> >  	status = "okay";
> >  };
> 


From heiko at sntech.de  Wed May 11 15:36:20 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Thu, 12 May 2016 00:36:20 +0200
Subject: [PATCH 2/2] ARM64: dts: rockchip: enable eMMC for rk3399 EVB
In-Reply-To: <20160511223233.GB65449@google.com>
References: <1462924975-69072-1-git-send-email-briannorris@chromium.org>
 <4355979.JCGxOmTVBW@phil> <20160511223233.GB65449@google.com>
Message-ID: <8868581.lJFUogXGzy@phil>

Am Mittwoch, 11. Mai 2016, 15:32:33 schrieb Brian Norris:
> On Wed, May 11, 2016 at 04:51:58PM +0200, Heiko Stuebner wrote:
> > Hi Brian,
> > 
> > Am Dienstag, 10. Mai 2016, 17:02:55 schrieb Brian Norris:
> > > The 'mmc-hs400-enhanced-strobe' property has been acked by Rob
> > > Herring,
> > > though it's still not merged.
> > 
> > The commit message should describe the actual change not the volatile
> > environment surrounding it :-) .
> > 
> > When I apply this patch the property-binding will have made it into a
> > maintainer-tree so is not valid anymore then. That is more material for
> > the "comment-section" below the "---"
> 
> Of course. I think I just felt guilty without a commit message :)

I really prefer a (even simple) message being there - although I'm not as 
strict as Greg and Felipe ;-) , and in cases like this I think something 
like "enable the newly added emmc node on the rk3399 evaluation board" 
should be sufficient.


Heiko



From dianders at chromium.org  Wed May 11 16:41:54 2016
From: dianders at chromium.org (Doug Anderson)
Date: Wed, 11 May 2016 16:41:54 -0700
Subject: [PATCH v8 8/8] i2c: rk3x: support fast-mode plus for rk3399
In-Reply-To: <5153288.jNhUuzGC3g@phil>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908794-27333-1-git-send-email-david.wu@rock-chips.com>
 <5153288.jNhUuzGC3g@phil>
Message-ID: <CAD=FV=VzQ8PRokgAaTV00L31mcXFEzBG8c1NB4+Rqyx75hwwDg@mail.gmail.com>

Heiko,

On Wed, May 11, 2016 at 2:09 PM, Heiko Stuebner <heiko at sntech.de> wrote:
> Additionally, the i2c-noob in me would wish for a short sentence on where
> the timing values come from (measured, somewhere in the TRM I didn't find or
> something completely different).

If you search for "UM10204" you'll find the first link is
<http://www.nxp.com/documents/user_manual/UM10204.pdf>.  That appears
to be the official standard.  At least that's what
<http://www.i2c-bus.org/fast-mode-plus/> says (though they have an old
link).

Agree that it wouldn't hurt to mention that in the commit message.

-Doug


From david.wu at rock-chips.com  Wed May 11 18:08:58 2016
From: david.wu at rock-chips.com (David.Wu)
Date: Thu, 12 May 2016 09:08:58 +0800
Subject: [PATCH v8 7/8] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <CAD=FV=Uf-U3RBpgFbR3LkPAJTWqz3d02+H7iyA-SS-y=r3cXjA@mail.gmail.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908698-27284-1-git-send-email-david.wu@rock-chips.com>
 <CAD=FV=Uf-U3RBpgFbR3LkPAJTWqz3d02+H7iyA-SS-y=r3cXjA@mail.gmail.com>
Message-ID: <5733D7AA.1060500@rock-chips.com>

Hi Doug,

? 2016/5/12 1:37, Doug Anderson ??:
> Hi,
>
> On Tue, May 10, 2016 at 12:31 PM, David Wu <david.wu at rock-chips.com> wrote:
>>   static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
>>   {
>>          struct i2c_timings *t = &i2c->t;
>>          struct rk3x_i2c_calced_timings calc;
>>          u64 t_low_ns, t_high_ns;
>> +       u32 val;
>>          int ret;
>>
>> -       ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
>> +       ret = i2c->soc_data->calc_timings(clk_rate, t, &calc);
>>          WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
>>
>> -       clk_enable(i2c->clk);
>> +       clk_enable(i2c->pclk);
>> +
>>          i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
>>                     REG_CLKDIV);
>> -       clk_disable(i2c->clk);
>> +
>> +       val = i2c_readl(i2c, REG_CON);
>> +       val &= ~REG_CON_TUNING_MASK;
>> +       val |= calc.tuning;
>> +       i2c_writel(i2c, val, REG_CON);
>
> Another subtle bug here.  You need to be holding the spinlock here
> since you're doing a read-modify-write of a register that is also
> touched by the interrupt handler.  We never needed it before because
> the previous register update wasn't touched by anyone else and it was
> a single atomic write.
>
> Also: technically if we are midway through a transfer when all this
> happens then there will be a very short period of time when the two
> timing-related registers won't match with each other.  I have no idea
> how much that would matter, but in the very least it seems wise to
> minimize the time where they mismatch.  So I'd probably write:
>
>         spin_lock_irqsave(&i2c->lock, flags);
>         val = i2c_readl(i2c, REG_CON);
>         val &= ~REG_CON_TUNING_MASK;
>         val |= calc.tuning;
>         i2c_writel(i2c, val, REG_CON);
>         i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
>                    REG_CLKDIV);
>         spin_unlock_irqrestore(&i2c->lock, flags);
>
> ...if we really end up with on a system with a dynamically changing
> clock that uses the new-style timing and we see real problems, we can
> always try to come up with a way to avoid any problems.  Sound OK?
>
>

Good, add spin_lock is very necessary for atomic write here, thanks for 
your advice.

> Otherwise, I think things look good to me.  Caesar's comments would
> also be good to fix.
>
>
> -Doug
>
>
>



From david.wu at rock-chips.com  Wed May 11 18:11:29 2016
From: david.wu at rock-chips.com (David.Wu)
Date: Thu, 12 May 2016 09:11:29 +0800
Subject: [PATCH v8 3/8] i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
In-Reply-To: <2477327.hJjg0APDhg@phil>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908252-27016-4-git-send-email-david.wu@rock-chips.com>
 <2477327.hJjg0APDhg@phil>
Message-ID: <5733D841.1020905@rock-chips.com>

Hi Heiko

? 2016/5/12 2:26, Heiko Stuebner ??:
> Am Mittwoch, 11. Mai 2016, 03:24:07 schrieb David Wu:
>> Call rk3x_i2c_setup() before rk3x_i2c_start()
>
> That beginning of the sentence could use a tiny improvement, like
>
> ----
> rk3x_i2c_setup() gets called directly before rk3x_i2c_start()
> ----
>

Okay, i will add it in next version, Thanks.

> to make it obvious what happens in the code.
>
> But a nice small improvement
> Reviewed-by: Heiko Stuebner <heiko at sntech.de>
>
>> and the last thing in setup was to clean the IPD,
>> so no reason to do it at the beginning of start.
>>
>> Signed-off-by: David Wu <david.wu at rock-chips.com>
>> Reviewed-by: Douglas Anderson <dianders at chromium.org>
>> ---
>> Change in v8:
>> - none
>>
>>   drivers/i2c/busses/i2c-rk3x.c | 1 -
>>   1 file changed, 1 deletion(-)
>>
>> diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
>> index 1e2677a..9eeb4e5 100644
>> --- a/drivers/i2c/busses/i2c-rk3x.c
>> +++ b/drivers/i2c/busses/i2c-rk3x.c
>> @@ -174,7 +174,6 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c)
>>   {
>>   	u32 val;
>>
>> -	rk3x_i2c_clean_ipd(i2c);
>>   	i2c_writel(i2c, REG_INT_START, REG_IEN);
>>
>>   	/* enable adapter with correct mode, send START condition */
>
>
>
>



From david.wu at rock-chips.com  Wed May 11 18:14:04 2016
From: david.wu at rock-chips.com (David.Wu)
Date: Thu, 12 May 2016 09:14:04 +0800
Subject: [PATCH v8 6/8] dt-bindings: i2c: rk3x: add support for rk3399
In-Reply-To: <CAD=FV=VzL8AfzUnPYgsf_NqPgbp2_o_qJC7-DWHmekWVQ-Es=A@mail.gmail.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908647-27236-1-git-send-email-david.wu@rock-chips.com>
 <CAD=FV=VzL8AfzUnPYgsf_NqPgbp2_o_qJC7-DWHmekWVQ-Es=A@mail.gmail.com>
Message-ID: <5733D8DC.1010603@rock-chips.com>

Hi Doug,

? 2016/5/12 0:35, Doug Anderson ??:
> Hi,
>
> On Tue, May 10, 2016 at 12:30 PM, David Wu <david.wu at rock-chips.com> wrote:
>> The bus clock and function clock are separated at rk3399,
>> and others use one clock as the bus clock and function clock.
>>
>> Signed-off-by: David Wu <david.wu at rock-chips.com>
>> Reviewed-by: Douglas Anderson <dianders at chromium.org>
>> ---
>> Change in v8:
>> - remove error description.
>>
>>   Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 16 +++++++++++++---
>>   1 file changed, 13 insertions(+), 3 deletions(-)
>>
>> diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
>> index 0b4a85f..5429301 100644
>> --- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
>> +++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
>> @@ -6,10 +6,20 @@ RK3xxx SoCs.
>>   Required properties :
>>
>>    - reg : Offset and length of the register set for the device
>> - - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c",
>> -               "rockchip,rk3228-i2c" or "rockchip,rk3288-i2c".
>> + - compatible: should be one of the following:
>> +   - "rockchip,rk3066-i2c": for rk3066
>> +   - "rockchip,rk3188-i2c": for rk3188
>> +   - "rockchip,rk3228-i2c": for rk3228
>> +   - "rockchip,rk3288-i2c": for rk3288
>> +   - "rockchip,rk3399-i2c": for rk3399
>>    - interrupts : interrupt number
>> - - clocks : parent clock
>> + - clocks: See ../clock/clock-bindings.txt
>> +   - For older hardware (rk3066, rk3188, rk3228, rk3288):
>> +     - There is one clock that's used both to derive the functional clock
>> +       for the device and as the bus clock.
>> +   - For newer hardware (rk3399): specified by name
>> +     - "i2c": REQUIRED. This is used to derive the functional clock.
>> +     - "pclk": REQUIRED. This is the bus clock.
>
> Depending on what Rob thinks, it might make sense to remove the above
> two "REQUIRED" bits.  That would match his earlier feedback since
> we're still in the "Required" section and thus it is redundant.
>

Okay, i make a little misunderstand for that, so i will fix it in next 
version.

> -Doug
>
>
>



From shawn.lin at kernel-upstream.org  Wed May 11 20:03:55 2016
From: shawn.lin at kernel-upstream.org (Shawn Lin)
Date: Thu, 12 May 2016 11:03:55 +0800
Subject: [PATCH 2/2] dt-bindings: rockchip-dw-mshc: add
 rockchip,default-drv-phase
In-Reply-To: <CAD=FV=V1dOsZkcFCd50N7F5qCVFMn789n3Hsopd7MDmdupim3Q@mail.gmail.com>
References: <1462527648-24443-1-git-send-email-shawn.lin@rock-chips.com>
 <1462527673-24711-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=WSkBwBjVsRoDsfjD+sNfR70mKGRA0khjPKKW0zS2=PTw@mail.gmail.com>
 <b15dcb4f-1584-8219-2fe0-97eecb0c64a6@rock-chips.com>
 <CAD=FV=XToSzqSh=SShHuQU9W_m7gfyQn8wRXkLy79t+tnqZknA@mail.gmail.com>
 <1f2f43c7-2672-e448-eddb-2d613bb8dc48@rock-chips.com>
 <CAD=FV=UGbrJRyUbbgzbcYf9GjPG+Fh_gpQ3rX2G=wi2w5Lw=Sg@mail.gmail.com>
 <e202f663-88d7-693b-a765-c130e68d1c2d@rock-chips.com>
 <CAD=FV=UyYCqMYKScjVEASrbzO75014kPCEt39uOSTsgq9M==YQ@mail.gmail.com>
 <2994d365-2cf2-0990-6c10-2abeebb42eef@rock-chips.com>
 <CAD=FV=V1dOsZkcFCd50N7F5qCVFMn789n3Hsopd7MDmdupim3Q@mail.gmail.com>
Message-ID: <d4447e52-81de-0ab6-7bd9-016a59f915a5@kernel-upstream.org>

? 2016/5/12 5:42, Doug Anderson ??:
> Shawn,
>
> On Wed, May 11, 2016 at 1:25 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> On 2016/5/11 11:50, Doug Anderson wrote:
>>>
>>> Hi,
>>>
>>> On Tue, May 10, 2016 at 7:50 PM, Shawn Lin <shawn.lin at rock-chips.com>
>>> wrote:
>>>>>>
>>>>>> maybe. But I think 180(downside) is the better.
>>>>
>>>>
>>>>
>>>> NAK my previous comments here. Downside is better for SRD, but won't
>>>> work for DDR mode. When running in DDR mode, we should use 90 instead.
>>>>
>>>> So let me elaborate a bit more here.
>>>> For DDR mode, one single clk cycle should sending two data bits outside
>>>> to the devices. We need a hold time for both. If 180 is used, the first
>>>> bit occurs around the downside area, which won't be sampled by devices
>>>> on the upside.  So on the upside, the devices will see a zero bit if you
>>>> actually send a one-bit, which makes the devices  generate CRC finally.
>>>>
>>>>
>>>> For this above, 180 for all SDR mode is ok, but 90 should be deployed
>>>> for DDR mode. So simply checking the timing to hardcode it should be
>>>> fine.
>>>
>>>
>>> OK, I sent out a patch for 180 always.  I can send v2 to use 90 for
>>> DDR modes tomorrow.  ...or feel free to post that yourself if you
>>> want.
>>>
>>> We want 90 for all DDR modes?  So MMC_TIMING_UHS_DDR50,
>>> MMC_TIMING_MMC_DDR52, MMC_TIMING_MMC_HS400? (not that we support HS400
>>> in dw_mmc on Rockchip).
>>
>>
>> Right.
>
> OK, so I dug into this more.  I don't think it's actually quite that
> simple.  The Designware databook explicitly states that 'MMC DDR
> 8-bit' should use 180, not 90.  ...but that's probably explained by
> the fact that "cclk_in" for MMC-DDR 8-bit is double what you'd expect.
> You can see that in code:
>
> if (ios->bus_width == MMC_BUS_WIDTH_8 &&
>     ios->timing == MMC_TIMING_MMC_DDR52)
>       cclkin = 2 * ios->clock * RK3288_CLKGEN_DIV;

Yes, this requirment is from dw_mmc databook(v270a), table 10-5.

But you can see that we didn't handle MMC_TIMING_UHS_SDR12.
As recommended, MMC_TIMING_UHS_SDR12 mode need to 50M here to make
the internal devider to be "1".
Because Figure 10-3 (Clock Structure for Host Controller) assumes Soc 
only supplies 50M/100M/200M, these three frequency selection, to 
cclk_in. So SDR12 should be 50M/2 = 25M. But for Rockchip Socs, we have 
RK3288_CLKGEN_DIV before cclk_in that means we don't follow this table.

For DDR52-8bit, it's a mandatory requirment to use 100M as cclk_in.

>
> ---
>
> tl;dr of all the below:
>
> * For SD: use 180 for SDR104 to get margin, use 90 elsewhere.
> * For mmc, use 180 for DDR52 to meet timings, use 180 for HS200 to get
> margin, use 90 elsewhere

yes, see the comments blow.

>
>
> The nice thing about this is, at least for rk3288, things don't change
> much from today where we use 90 degrees for most SD cards.
>
> ---
>
> For new patch, see: <https://patchwork.kernel.org/patch/9075141/>
>
> ---
>
> Details:
>
> So assuming measurements I saw from an EE are correct, measured
> "delay_o_ns" is ~ .5 ns for rk3399.  With that, we can do some math.

Soc specific. But it's a trivial margin.

> Please correct any mistakes.  Math is hard.  Note that on all Rockchip
> devices I've seen pins are limited to 150 MHz and when we choose 150
> MHz we end up at 148.5 MHz.  Calculations aren't too different if we
> use 150 for that case.
>
>
> MMC_TIMING_MMC_DDR52:
>   min hold time = 2.5 ns
>   min data delay = 2.5 ns + .5 ns = 3 ns
>   with 100 MHz clock, 90 degree: 2.5 ns
>   with 100 MHz clock, 180 degree: 5.0 ns
>
>   ...need 180 degree
>

When running in DDR52-8bit, 2 cycle of cclk_in is used
for a single data bit internally. When shifting cclk_in_drv to 180,
we can see:

cclk_in    ____      ____      ____      ____      ___
	__|    |____|    |____|    |____|    |____|

cclk_in_drv-180
                 ____      ____      ____      ____      ___
	     __|    |____|    |____|    |____|    |____|

cclk_in_for_DDR52-8bit
            _________           _____
         __|         |_________|



So cclk_in_drv shifts 180 from cclk_in, which means it's just in the
90 degrees of cclk_in_for_DDR52-8bit. That is what I'd expect that when
running in DDR mode, the cclk_in_drv should be in the 90 degree of
*Actual Internal CLK*, not cclk_in always.

But fot SD DDR50-4bit, it just use cclk_in internlly, so 90 should
be okay.

So we were not in the same page of what the ref-clk is. But I think now
we are in.

Agree on all the calculation below.

> --
>
> SD DDR50:
>   min hold time = .8 ns
>   min data delay = .8 ns + .5 ns = 1.3 ns
>   with 50 MHz clock, 90 degree: 5 ns
>   with 50 MHz clock, 180 degree: 10 ns
>
>   ...90 degree is good and 180 is massive overkill.  Use 90.
>
> --
>
> SD SDR104 (limited to 148.5 MHz on existing Rockchip parts):
>   min hold time = .8 ns
>   min data delay = .8 ns + .5 ns = 1.3 ns
>   with 148.5 MHz clock, 90 degree: 1.68 ns
>   with 148.5 MHz clock, 180 degree: 3.37 ns
>
>   ...so 90 degrees would probably work OK, but 180 degrees gives more margin.
>   ...probably explains why existing rk3288 devices w/ 90 degree work OK.
>
>   if we had 200 MHz clock, 90 degree: 1.25 ns
>   if we had 200 MHz clock, 180 degree: 2.50 ns
>
> --
>
> SD SDR50:
>   min hold time = .8 ns
>   min data delay = .8 ns + .5 ns = 1.3 ns
>   with 100 MHz clock, 90 degree: 2.5 ns
>   with 100 MHz clock, 180 degree: 5.0 ns
>
>   ...90 degree is great w/ plenty of margin
>
> --
>
> SD SDR25:
>   min hold time = 2 ns
>   min data delay = 2 ns + .5 ns = 2.5 ns
>   with 50 MHz clock, 90 degree: 5 ns
>   with 50 MHz clock, 180 degree: 10 ns
>
>  ...90 degree is good and 180 is massive overkill.  Use 90.
>
> --
>
> SD SDR12 (databook shows cclk_in as 50 MHz here we'll get 25 MHz):
>   min hold time = 5 ns
>   min data delay = 5 ns + .5 ns = 5.5 ns
>   with 25 MHz clock, 90 degree: 10 ns
>   with 25 MHz clock, 180 degree: 20 ns
>
>   ...90 degree is good (databook suggests 180 for this mode due to cclk_in = 50)
>
> --
>
> ID Mode
>   min hold time = 5 ns
>   min data delay = 5 ns + .5 ns = 5.5 ns
>   with 400 kHz clock, 90 degree: 625 ns
>   with 400 kHz clock, 180 degree: 1250 ns
>
>   ...90 degree is good  (databook suggests 180 for this mode due to
> cclk_in = 50)
>
> --
>
> MMC High speed:
>   min hold time = 2.5 ns
>   min data delay = 2.5 ns + .5 ns = 3 ns
>   with 50 MHz clock, 90 degree: 5 ns
>   with 50 MHz clock, 180 degree: 10 ns
>
>   ...90 degree is good
>
> --
>
> HS200:
>   min hold time (tIH from JEDEC spec):  .8 ns
>   ...math all works out the same as SDR104.
>
> --
>
> HS400:
>   we don't support it anyway
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



From shawn.lin at rock-chips.com  Wed May 11 20:13:54 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 12 May 2016 11:13:54 +0800
Subject: [PATCH v2] mmc: dw_mmc: rockchip: Set the drive phase properly
In-Reply-To: <1463002848-580-1-git-send-email-dianders@chromium.org>
References: <1463002848-580-1-git-send-email-dianders@chromium.org>
Message-ID: <4ea71cf9-873f-960a-67cb-54da603fd628@rock-chips.com>

On 2016/5/12 5:40, Douglas Anderson wrote:
> Historically for Rockchip devices we've relied on the power-on
> default (or perhaps the firmware setting) to get the correct drive
> phase for dw_mmc devices.  This worked OK for the most part, but:
>
> * Relying on the setting just "being right" is a bit fragile.
>
> * As soon as there is an instance where the power on default is wrong or
>   where the firmware didn't configure this properly then we'll get a
>   mysterious failure.
>
> Let's explicitly set this phase in the kernel.
>
> The comments inside this patch try to explain the situation quite
> throughly, but the high level overview of this is:
>
> Before this patch on rk3288 devices tested:
> * eMMC: 180 degrees
> * SDMMC/SDIO0/SDIO1: 90 degrees
>
> After this patch:
> * Use 90 degree phase offset usually.
> * Use 180 degree phase offset for MMC_DDR52, SDR104, HS200.

Thanks for doing this.

Reviewed-by: Shawn Lin<shawn.lin at rock-chips.com>

>
> That means we are _changing_ behavior for those devices in this way:
>
> * If we have HS200 eMMC or DDR52 eMMC, we'll run ID mode at 90
>   degrees (vs 180) but otherwise have no change.
>
> * For any non-HS200 / non-DDR52 eMMC devices we'll now _always_ run at
>   90 degrees (vs 180).  It seems fairly unlikely that building modern
>   hardware is using an eMMC that isn't using DDR52 or HS200, of course.
>
> * For SDR104 cards we'll now run with 180 degree phase offset (vs 90).
>   It's expected that 90 degree phase offset would have worked OK, but
>   this gives us extra margin.
>
> I have tested this by inserting my collection of uSD cards (mostly UHS,
> though a few not) into a veyron_minnie and confirmed that they still
> seem to enumerate properly.  For a subset of them I tried putting a
> filesystem on them and also tried running mmc_test.
>
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> ---
> Changes in v2:
> - Now use 90 degrees for some modes; updated comments to say why.
>
>  drivers/mmc/host/dw_mmc-rockchip.c | 64 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 64 insertions(+)
>
> diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
> index 8c20b81cafd8..8068fa887db8 100644
> --- a/drivers/mmc/host/dw_mmc-rockchip.c
> +++ b/drivers/mmc/host/dw_mmc-rockchip.c
> @@ -66,6 +66,70 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
>  	/* Make sure we use phases which we can enumerate with */
>  	if (!IS_ERR(priv->sample_clk))
>  		clk_set_phase(priv->sample_clk, priv->default_sample_phase);
> +
> +	/*
> +	 * Set the drive phase offset based on speed mode to achieve hold times.
> +	 *
> +	 * That this is _not_ a value that is dynamically tuned and is also
> +	 * _not_ a value that will vary from board to board.  It is a value
> +	 * that could vary between different SoC models if they had massively
> +	 * different output clock delays inside their dw_mmc IP block (delay_o),
> +	 * but since it's OK to overshoot a little we don't need to do complex
> +	 * calculations and can pick values that will just work for everyone.
> +	 *
> +	 * When picking values we'll stick with picking 0/90/180/270 since
> +	 * those can be made very accurately on all known Rockchip SoCs.
> +	 *
> +	 * Note that these values match values from the DesignWare Databook
> +	 * tables for the most part except for SDR12 and "ID mode".  For those
> +	 * two modes the databook calculations assume a clock in of 50MHz.  As
> +	 * seen above, we always use a clock in rate that is exactly the
> +	 * card's input clock (times RK3288_CLKGEN_DIV, but that gets divided
> +	 * back out before the controller sees it).
> +	 *
> +	 * From measurement of a single device, it appears that delay_o is
> +	 * about .5 ns.  Since we try to leave a bit of margin, it's expected
> +	 * that numbers here will be fine even with much larger delay_o
> +	 * (the 1.4 ns assumed by the DesignWare Databook would result in the
> +	 * same results, for instance).
> +	 */
> +	if (!IS_ERR(priv->drv_clk)) {
> +		int phase;
> +
> +		/*
> +		 * In almost all cases a 90 degree phase offset will provide
> +		 * sufficient hold times across all valid input clock rates
> +		 * assuming delay_o is not absurd for a given SoC.  We'll use
> +		 * that as a default.
> +		 */
> +		phase = 90;
> +
> +		switch (ios->timing) {
> +		case MMC_TIMING_MMC_DDR52:
> +			/*
> +			 * Since clock in rate with MMC_DDR52 is doubled when
> +			 * bus width is 8 we need to double the phase offset
> +			 * to get the same timings.
> +			 */
> +			if (ios->bus_width == MMC_BUS_WIDTH_8)
> +				phase = 180;
> +			break;
> +		case MMC_TIMING_UHS_SDR104:
> +		case MMC_TIMING_MMC_HS200:
> +			/*
> +			 * In the case of 150 MHz clock (typical max for
> +			 * Rockchip SoCs), 90 degree offset will add a delay
> +			 * of 1.67 ns.  That will meet min hold time of .8 ns
> +			 * as long as clock output delay is < .87 ns.  On
> +			 * SoCs measured this seems to be OK, but it doesn't
> +			 * hurt to give margin here, so we use 180.
> +			 */
> +			phase = 180;
> +			break;
> +		}
> +
> +		clk_set_phase(priv->drv_clk, phase);
> +	}
>  }
>
>  #define NUM_PHASES			360
>


-- 
Best Regards
Shawn Lin



From david.wu at rock-chips.com  Thu May 12 00:52:58 2016
From: david.wu at rock-chips.com (David Wu)
Date: Thu, 12 May 2016 15:52:58 +0800
Subject: [PATCH v9 0/8] add i2c driver supported for rk3399
Message-ID: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>

There are three points differert from others:
 - new method to caculate i2c timings for rk3399
 - pclk and function clk are separated at rk3399
 - add fast-plus mode supported for rk3399

David Wu (8):
  i2c: rk3x: add documentation to fields in "struct rk3x_i2c"
  i2c: rk3x: use struct "rk3x_i2c_calced_timings"
  i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
  i2c: rk3x: Change SoC data to not use array
  i2c: rk3x: Move spec timing data to "static const" structs
  dt-bindings: i2c: rk3x: add support for rk3399
  i2c: rk3x: add i2c support for rk3399 soc
  i2c: rk3x: support fast-mode plus for rk3399

 Documentation/devicetree/bindings/i2c/i2c-rk3x.txt |  16 +-
 drivers/i2c/busses/i2c-rk3x.c                      | 495 +++++++++++++++++----
 2 files changed, 432 insertions(+), 79 deletions(-)

-- 
1.9.1




From david.wu at rock-chips.com  Thu May 12 00:52:59 2016
From: david.wu at rock-chips.com (David Wu)
Date: Thu, 12 May 2016 15:52:59 +0800
Subject: [PATCH v9 1/8] i2c: rk3x: add documentation to fields in "struct
 rk3x_i2c"
In-Reply-To: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
References: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463039586-8134-2-git-send-email-david.wu@rock-chips.com>

Add kernel-doc documentation for the elements of the previously
undocumented struct rk3x_i2c.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v9:
- add commit description.

Change in v8:
- none

 drivers/i2c/busses/i2c-rk3x.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 80bed02..7e45d51 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -90,6 +90,26 @@ struct rk3x_i2c_soc_data {
 	int grf_offset;
 };
 
+/**
+ * struct rk3x_i2c - private data of the controller
+ * @adap: corresponding I2C adapter
+ * @dev: device for this controller
+ * @soc_data: related soc data struct
+ * @regs: virtual memory area
+ * @clk: clock of i2c bus
+ * @clk_rate_nb: i2c clk rate change notify
+ * @t: I2C known timing information
+ * @lock: spinlock for the i2c bus
+ * @wait: the waitqueue to wait for i2c transfer
+ * @busy: the condition for the event to wait for
+ * @msg: current i2c message
+ * @addr: addr of i2c slave device
+ * @mode: mode of i2c transfer
+ * @is_last_msg: flag determines whether it is the last msg in this transfer
+ * @state: state of i2c transfer
+ * @processed: byte length which has been send or received
+ * @error: error code for i2c transfer
+ */
 struct rk3x_i2c {
 	struct i2c_adapter adap;
 	struct device *dev;
@@ -116,7 +136,7 @@ struct rk3x_i2c {
 
 	/* I2C state machine */
 	enum rk3x_i2c_state state;
-	unsigned int processed; /* sent/received bytes */
+	unsigned int processed;
 	int error;
 };
 
-- 
1.9.1




From david.wu at rock-chips.com  Thu May 12 00:53:00 2016
From: david.wu at rock-chips.com (David Wu)
Date: Thu, 12 May 2016 15:53:00 +0800
Subject: [PATCH v9 2/8] i2c: rk3x: use struct "rk3x_i2c_calced_timings"
In-Reply-To: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
References: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463039586-8134-3-git-send-email-david.wu@rock-chips.com>

The "div_high" and "div_low" values are always used together.
Group them into a structure to make it easier to pass them
both around. This structure also provides a place for future
calculated timings.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
---
Change in v9:
- none

Change in v8:
- add commit description.

 drivers/i2c/busses/i2c-rk3x.c | 55 +++++++++++++++++++++++++------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 7e45d51..1e2677a 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -75,6 +75,16 @@ enum {
 #define WAIT_TIMEOUT      1000 /* ms */
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
+/**
+ * struct rk3x_i2c_calced_timings:
+ * @div_low: Divider output for low
+ * @div_high: Divider output for high
+ */
+struct rk3x_i2c_calced_timings {
+	unsigned long div_low;
+	unsigned long div_high;
+};
+
 enum rk3x_i2c_state {
 	STATE_IDLE,
 	STATE_START,
@@ -454,9 +464,8 @@ out:
  * Calculate divider values for desired SCL frequency
  *
  * @clk_rate: I2C input clock rate
- * @t: Known I2C timing information.
- * @div_low: Divider output for low
- * @div_high: Divider output for high
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
  *
  * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
@@ -464,8 +473,7 @@ out:
  */
 static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 			      struct i2c_timings *t,
-			      unsigned long *div_low,
-			      unsigned long *div_high)
+			      struct rk3x_i2c_calced_timings *t_calc)
 {
 	unsigned long spec_min_low_ns, spec_min_high_ns;
 	unsigned long spec_setup_start, spec_max_data_hold_ns;
@@ -572,8 +580,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 		 * Time needed to meet hold requirements is important.
 		 * Just use that.
 		 */
-		*div_low = min_low_div;
-		*div_high = min_high_div;
+		t_calc->div_low = min_low_div;
+		t_calc->div_high = min_high_div;
 	} else {
 		/*
 		 * We've got to distribute some time among the low and high
@@ -602,25 +610,25 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 
 		/* Give low the "ideal" and give high whatever extra is left */
 		extra_low_div = ideal_low_div - min_low_div;
-		*div_low = ideal_low_div;
-		*div_high = min_high_div + (extra_div - extra_low_div);
+		t_calc->div_low = ideal_low_div;
+		t_calc->div_high = min_high_div + (extra_div - extra_low_div);
 	}
 
 	/*
 	 * Adjust to the fact that the hardware has an implicit "+1".
 	 * NOTE: Above calculations always produce div_low > 0 and div_high > 0.
 	 */
-	*div_low = *div_low - 1;
-	*div_high = *div_high - 1;
+	t_calc->div_low--;
+	t_calc->div_high--;
 
 	/* Maximum divider supported by hw is 0xffff */
-	if (*div_low > 0xffff) {
-		*div_low = 0xffff;
+	if (t_calc->div_low > 0xffff) {
+		t_calc->div_low = 0xffff;
 		ret = -EINVAL;
 	}
 
-	if (*div_high > 0xffff) {
-		*div_high = 0xffff;
+	if (t_calc->div_high > 0xffff) {
+		t_calc->div_high = 0xffff;
 		ret = -EINVAL;
 	}
 
@@ -630,19 +638,21 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 {
 	struct i2c_timings *t = &i2c->t;
-	unsigned long div_low, div_high;
+	struct rk3x_i2c_calced_timings calc;
 	u64 t_low_ns, t_high_ns;
 	int ret;
 
-	ret = rk3x_i2c_calc_divs(clk_rate, t, &div_low, &div_high);
+	ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
 	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
 
 	clk_enable(i2c->clk);
-	i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV);
+	i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
+		   REG_CLKDIV);
 	clk_disable(i2c->clk);
 
-	t_low_ns = div_u64(((u64)div_low + 1) * 8 * 1000000000, clk_rate);
-	t_high_ns = div_u64(((u64)div_high + 1) * 8 * 1000000000, clk_rate);
+	t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
+	t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
+			    clk_rate);
 	dev_dbg(i2c->dev,
 		"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
 		clk_rate / 1000,
@@ -672,12 +682,11 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
 {
 	struct clk_notifier_data *ndata = data;
 	struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
-	unsigned long div_low, div_high;
+	struct rk3x_i2c_calced_timings calc;
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
-		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t,
-				       &div_low, &div_high) != 0)
+		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0)
 			return NOTIFY_STOP;
 
 		/* scale up */
-- 
1.9.1




From david.wu at rock-chips.com  Thu May 12 00:53:01 2016
From: david.wu at rock-chips.com (David Wu)
Date: Thu, 12 May 2016 15:53:01 +0800
Subject: [PATCH v9 3/8] i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
In-Reply-To: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
References: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463039586-8134-4-git-send-email-david.wu@rock-chips.com>

rk3x_i2c_setup() gets called directly before rk3x_i2c_start(),
and the last thing in setup was to clean the IPD, so no reason
to do it at the beginning of start.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v9:
- modify commit message

Change in v8:
- none

 drivers/i2c/busses/i2c-rk3x.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 1e2677a..9eeb4e5 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -174,7 +174,6 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
 	u32 val;
 
-	rk3x_i2c_clean_ipd(i2c);
 	i2c_writel(i2c, REG_INT_START, REG_IEN);
 
 	/* enable adapter with correct mode, send START condition */
-- 
1.9.1




From david.wu at rock-chips.com  Thu May 12 00:53:02 2016
From: david.wu at rock-chips.com (David Wu)
Date: Thu, 12 May 2016 15:53:02 +0800
Subject: [PATCH v9 4/8] i2c: rk3x: Change SoC data to not use array
In-Reply-To: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
References: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463039586-8134-5-git-send-email-david.wu@rock-chips.com>

Specifying the i2c SoC data in an array provides very little benefit and
gets unwieldly / confusing as the array grows since the next bit of code
needs to refer to elements in the array by their raw integral index.

Let's just create a single 'static const' structure for each SoC so that
we can refer to these structures by ID.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Suggested-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
---
Change in v9:
- none

Change in v8:
- add commit description.

 drivers/i2c/busses/i2c-rk3x.c | 38 ++++++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 9eeb4e5..d7a871f 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -864,17 +864,39 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
 	.functionality		= rk3x_i2c_func,
 };
 
-static struct rk3x_i2c_soc_data soc_data[3] = {
-	{ .grf_offset = 0x154 }, /* rk3066 */
-	{ .grf_offset = 0x0a4 }, /* rk3188 */
-	{ .grf_offset = -1 },    /* no I2C switching needed */
+static const struct rk3x_i2c_soc_data rk3066_soc_data = {
+	.grf_offset = 0x154,
+};
+
+static const struct rk3x_i2c_soc_data rk3188_soc_data = {
+	.grf_offset = 0x0a4,
+};
+
+static const struct rk3x_i2c_soc_data rk3228_soc_data = {
+	.grf_offset = -1,
+};
+
+static const struct rk3x_i2c_soc_data rk3288_soc_data = {
+	.grf_offset = -1,
 };
 
 static const struct of_device_id rk3x_i2c_match[] = {
-	{ .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] },
-	{ .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] },
-	{ .compatible = "rockchip,rk3228-i2c", .data = (void *)&soc_data[2] },
-	{ .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] },
+	{
+		.compatible = "rockchip,rk3066-i2c",
+		.data = (void *)&rk3066_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3188-i2c",
+		.data = (void *)&rk3188_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3228-i2c",
+		.data = (void *)&rk3228_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3288-i2c",
+		.data = (void *)&rk3288_soc_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
-- 
1.9.1




From david.wu at rock-chips.com  Thu May 12 00:57:09 2016
From: david.wu at rock-chips.com (David Wu)
Date: Thu, 12 May 2016 15:57:09 +0800
Subject: [PATCH v9 5/8] i2c: rk3x: Move spec timing data to "static const"
 structs
In-Reply-To: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
References: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463039829-8267-1-git-send-email-david.wu@rock-chips.com>

The i2c timing specs are really just constant data. There's no reason
to write code to init them, so move them out to structures. This not
only is a cleaner solution but it will reduce code duplication when we
introduce a new variant of rk3x_i2c_calc_divs() in a future patch.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Suggested-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
---
Change in v9:
- none

Changes in v8:
- add commit description.
- remove the spec values that were not needed, then
  introduce the additional values in the rk3399 patch. 

 drivers/i2c/busses/i2c-rk3x.c | 83 ++++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 28 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index d7a871f..9791797 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -76,6 +76,34 @@ enum {
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
 /**
+ * struct i2c_spec_values:
+ * @min_low_ns: min LOW period of the SCL clock
+ * @min_high_ns: min HIGH period of the SCL cloc
+ * @min_setup_start_ns: min set-up time for a repeated START conditio
+ * @max_data_hold_ns: max data hold time
+ */
+struct i2c_spec_values {
+	unsigned long min_low_ns;
+	unsigned long min_high_ns;
+	unsigned long min_setup_start_ns;
+	unsigned long max_data_hold_ns;
+};
+
+static const struct i2c_spec_values standard_mode_spec = {
+	.min_low_ns = 4700,
+	.min_high_ns = 4000,
+	.min_setup_start_ns = 4700,
+	.max_data_hold_ns = 3450,
+};
+
+static const struct i2c_spec_values fast_mode_spec = {
+	.min_low_ns = 1300,
+	.min_high_ns = 600,
+	.min_setup_start_ns = 600,
+	.max_data_hold_ns = 900,
+};
+
+/**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
  * @div_high: Divider output for high
@@ -460,6 +488,21 @@ out:
 }
 
 /**
+ * Get timing values of I2C specification
+ *
+ * @speed: Desired SCL frequency
+ *
+ * Returns: Matched i2c spec values.
+ */
+static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
+{
+	if (speed <= 100000)
+		return &standard_mode_spec;
+	else
+		return &fast_mode_spec;
+}
+
+/**
  * Calculate divider values for desired SCL frequency
  *
  * @clk_rate: I2C input clock rate
@@ -474,10 +517,6 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 			      struct i2c_timings *t,
 			      struct rk3x_i2c_calced_timings *t_calc)
 {
-	unsigned long spec_min_low_ns, spec_min_high_ns;
-	unsigned long spec_setup_start, spec_max_data_hold_ns;
-	unsigned long data_hold_buffer_ns;
-
 	unsigned long min_low_ns, min_high_ns;
 	unsigned long max_low_ns, min_total_ns;
 
@@ -489,6 +528,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	unsigned long min_div_for_hold, min_total_div;
 	unsigned long extra_div, extra_low_div, ideal_low_div;
 
+	unsigned long data_hold_buffer_ns = 50;
+	const struct i2c_spec_values *spec;
 	int ret = 0;
 
 	/* Only support standard-mode and fast-mode */
@@ -511,22 +552,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	 *	 This is because the i2c host on Rockchip holds the data line
 	 *	 for half the low time.
 	 */
-	if (t->bus_freq_hz <= 100000) {
-		/* Standard-mode */
-		spec_min_low_ns = 4700;
-		spec_setup_start = 4700;
-		spec_min_high_ns = 4000;
-		spec_max_data_hold_ns = 3450;
-		data_hold_buffer_ns = 50;
-	} else {
-		/* Fast-mode */
-		spec_min_low_ns = 1300;
-		spec_setup_start = 600;
-		spec_min_high_ns = 600;
-		spec_max_data_hold_ns = 900;
-		data_hold_buffer_ns = 50;
-	}
-	min_high_ns = t->scl_rise_ns + spec_min_high_ns;
+	spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+	min_high_ns = t->scl_rise_ns + spec->min_high_ns;
 
 	/*
 	 * Timings for repeated start:
@@ -536,14 +563,14 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	 * We need to account for those rules in picking our "high" time so
 	 * we meet tSU;STA and tHD;STA times.
 	 */
-	min_high_ns = max(min_high_ns,
-		DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875));
-	min_high_ns = max(min_high_ns,
-		DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start +
-			      t->sda_fall_ns + spec_min_high_ns), 2));
-
-	min_low_ns = t->scl_fall_ns + spec_min_low_ns;
-	max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
+	min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+		(t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875));
+	min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+		(t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns +
+		spec->min_high_ns), 2));
+
+	min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+	max_low_ns =  spec->max_data_hold_ns * 2 - data_hold_buffer_ns;
 	min_total_ns = min_low_ns + min_high_ns;
 
 	/* Adjust to avoid overflow */
-- 
1.9.1




From david.wu at rock-chips.com  Thu May 12 00:57:59 2016
From: david.wu at rock-chips.com (David Wu)
Date: Thu, 12 May 2016 15:57:59 +0800
Subject: [PATCH v9 6/8] dt-bindings: i2c: rk3x: add support for rk3399
In-Reply-To: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
References: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463039879-8318-1-git-send-email-david.wu@rock-chips.com>

The bus clock and function clock are separated at rk3399,
and others use one clock as the bus clock and function clock.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v9:
- remove unnecessary "REQUIRED".

Change in v8:
- remove error description.

 Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
index 0b4a85f..bbc5a1e 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
@@ -6,10 +6,20 @@ RK3xxx SoCs.
 Required properties :
 
  - reg : Offset and length of the register set for the device
- - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c",
-		"rockchip,rk3228-i2c" or "rockchip,rk3288-i2c".
+ - compatible: should be one of the following:
+   - "rockchip,rk3066-i2c": for rk3066
+   - "rockchip,rk3188-i2c": for rk3188
+   - "rockchip,rk3228-i2c": for rk3228
+   - "rockchip,rk3288-i2c": for rk3288
+   - "rockchip,rk3399-i2c": for rk3399
  - interrupts : interrupt number
- - clocks : parent clock
+ - clocks: See ../clock/clock-bindings.txt
+   - For older hardware (rk3066, rk3188, rk3228, rk3288):
+     - There is one clock that's used both to derive the functional clock
+       for the device and as the bus clock.
+   - For newer hardware (rk3399): specified by name
+     - "i2c": This is used to derive the functional clock.
+     - "pclk": This is the bus clock.
 
 Required on RK3066, RK3188 :
 
-- 
1.9.1




From david.wu at rock-chips.com  Thu May 12 00:58:50 2016
From: david.wu at rock-chips.com (David Wu)
Date: Thu, 12 May 2016 15:58:50 +0800
Subject: [PATCH v9 7/8] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
References: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463039930-8367-1-git-send-email-david.wu@rock-chips.com>

- new method to caculate i2c timings for rk3399:
  There was an timing issue about "repeated start" time at the I2C
  controller of version0, controller appears to drop SDA at .875x (7/8)
  programmed clk high. On version 1 of the controller, the rule(.875x)
  isn't enough to meet tSU;STA
  requirements on 100k's Standard-mode. To resolve this issue,
  sda_update_config, start_setup_config and stop_setup_config for I2C
  timing information are added, new rules are designed to calculate
  the timing information at new v1.
- pclk and function clk are separated at rk3399

Signed-off-by: David Wu <david.wu at rock-chips.com>
Tested-by: Caesar Wang <wxt at rock-chips.com>
---
Change in v9:
- add spin lock for tuning updated in rk3x_i2c_adapt_div() (Doug) 

Changes in v8:
- update tuning in RKI2C_CON register by doing a read-modify-write (Doug)
- new method to use pclk and clk (Doug)

Changes in v7:
- transform into a 9 series patches (Doug)
- drop highspeed with mastercode, and support fast-mode plus (Doug)

 drivers/i2c/busses/i2c-rk3x.c | 291 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 272 insertions(+), 19 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 9791797..673656e 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -58,6 +58,12 @@ enum {
 #define REG_CON_LASTACK   BIT(5) /* 1: send NACK after last received byte */
 #define REG_CON_ACTACK    BIT(6) /* 1: stop if NACK is received */
 
+#define REG_CON_TUNING_MASK GENMASK(15, 8)
+
+#define REG_CON_SDA_CFG(cfg) ((cfg) << 8)
+#define REG_CON_STA_CFG(cfg) ((cfg) << 12)
+#define REG_CON_STO_CFG(cfg) ((cfg) << 14)
+
 /* REG_MRXADDR bits */
 #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
 
@@ -77,40 +83,62 @@ enum {
 
 /**
  * struct i2c_spec_values:
+ * @min_hold_start_ns: min hold time (repeated) START condition
  * @min_low_ns: min LOW period of the SCL clock
  * @min_high_ns: min HIGH period of the SCL cloc
  * @min_setup_start_ns: min set-up time for a repeated START conditio
  * @max_data_hold_ns: max data hold time
+ * @min_data_setup_ns: min data set-up time
+ * @min_setup_stop_ns: min set-up time for STOP condition
+ * @min_hold_buffer_ns: min bus free time between a STOP and
+ * START condition
  */
 struct i2c_spec_values {
+	unsigned long min_hold_start_ns;
 	unsigned long min_low_ns;
 	unsigned long min_high_ns;
 	unsigned long min_setup_start_ns;
 	unsigned long max_data_hold_ns;
+	unsigned long min_data_setup_ns;
+	unsigned long min_setup_stop_ns;
+	unsigned long min_hold_buffer_ns;
 };
 
 static const struct i2c_spec_values standard_mode_spec = {
+	.min_hold_start_ns = 4000,
 	.min_low_ns = 4700,
 	.min_high_ns = 4000,
 	.min_setup_start_ns = 4700,
 	.max_data_hold_ns = 3450,
+	.min_data_setup_ns = 250,
+	.min_setup_stop_ns = 4000,
+	.min_hold_buffer_ns = 4700,
 };
 
 static const struct i2c_spec_values fast_mode_spec = {
+	.min_hold_start_ns = 600,
 	.min_low_ns = 1300,
 	.min_high_ns = 600,
 	.min_setup_start_ns = 600,
 	.max_data_hold_ns = 900,
+	.min_data_setup_ns = 100,
+	.min_setup_stop_ns = 600,
+	.min_hold_buffer_ns = 1300,
 };
 
 /**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
  * @div_high: Divider output for high
+ * @tuning: Used to adjust setup/hold data time,
+ * setup/hold start time and setup stop time for
+ * v1's calc_timings, the tuning should all be 0
+ * for old hardware anyone using v0's calc_timings.
  */
 struct rk3x_i2c_calced_timings {
 	unsigned long div_low;
 	unsigned long div_high;
+	unsigned int tuning;
 };
 
 enum rk3x_i2c_state {
@@ -123,9 +151,12 @@ enum rk3x_i2c_state {
 
 /**
  * @grf_offset: offset inside the grf regmap for setting the i2c type
+ * @calc_timings: Callback function for i2c timing information calculated
  */
 struct rk3x_i2c_soc_data {
 	int grf_offset;
+	int (*calc_timings)(unsigned long, struct i2c_timings *,
+			    struct rk3x_i2c_calced_timings *);
 };
 
 /**
@@ -134,7 +165,8 @@ struct rk3x_i2c_soc_data {
  * @dev: device for this controller
  * @soc_data: related soc data struct
  * @regs: virtual memory area
- * @clk: clock of i2c bus
+ * @clk: function clk for rk3399 or function & Bus clks for others
+ * @pclk: Bus clk for rk3399
  * @clk_rate_nb: i2c clk rate change notify
  * @t: I2C known timing information
  * @lock: spinlock for the i2c bus
@@ -156,6 +188,7 @@ struct rk3x_i2c {
 	/* Hardware resources */
 	void __iomem *regs;
 	struct clk *clk;
+	struct clk *pclk;
 	struct notifier_block clk_rate_nb;
 
 	/* Settings */
@@ -200,12 +233,12 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
  */
 static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
-	u32 val;
+	u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
 
 	i2c_writel(i2c, REG_INT_START, REG_IEN);
 
 	/* enable adapter with correct mode, send START condition */
-	val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
+	val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
 
 	/* if we want to react to NACK, set ACTACK bit */
 	if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
@@ -513,9 +546,9 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
  * a best-effort divider value is returned in divs. If the target rate is
  * too high, we silently use the highest possible rate.
  */
-static int rk3x_i2c_calc_divs(unsigned long clk_rate,
-			      struct i2c_timings *t,
-			      struct rk3x_i2c_calced_timings *t_calc)
+static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
+				    struct i2c_timings *t,
+				    struct rk3x_i2c_calced_timings *t_calc)
 {
 	unsigned long min_low_ns, min_high_ns;
 	unsigned long max_low_ns, min_total_ns;
@@ -661,20 +694,191 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	return ret;
 }
 
+/**
+ * Calculate timing values for desired SCL frequency
+ *
+ * @clk_rate: I2C input clock rate
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
+ *
+ * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
+ * a best-effort divider value is returned in divs. If the target rate is
+ * too high, we silently use the highest possible rate.
+ * The following formulas are v1's method to calculate timings.
+ *
+ * l = divl + 1;
+ * h = divh + 1;
+ * s = sda_update_config + 1;
+ * u = start_setup_config + 1;
+ * p = stop_setup_config + 1;
+ * T = Tclk_i2c;
+ *
+ * tHigh = 8 * h * T;
+ * tLow = 8 * l * T;
+ *
+ * tHD;sda = (l * s + 1) * T;
+ * tSU;sda = [(8 - s) * l + 1] * T;
+ * tI2C = 8 * (l + h) * T;
+ *
+ * tSU;sta = (8h * u + 1) * T;
+ * tHD;sta = [8h * (u + 1) - 1] * T;
+ * tSU;sto = (8h * p + 1) * T;
+ */
+static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
+				    struct i2c_timings *t,
+				    struct rk3x_i2c_calced_timings *t_calc)
+{
+	unsigned long min_low_ns, min_high_ns, min_total_ns;
+	unsigned long min_setup_start_ns, min_setup_data_ns;
+	unsigned long min_setup_stop_ns, max_hold_data_ns;
+
+	unsigned long clk_rate_khz, scl_rate_khz;
+
+	unsigned long min_low_div, min_high_div;
+
+	unsigned long min_div_for_hold, min_total_div;
+	unsigned long extra_div, extra_low_div;
+	unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg;
+
+	const struct i2c_spec_values *spec;
+	int ret = 0;
+
+	/* Support standard-mode and fast-mode */
+	if (WARN_ON(t->bus_freq_hz > 400000))
+		t->bus_freq_hz = 400000;
+
+	/* prevent scl_rate_khz from becoming 0 */
+	if (WARN_ON(t->bus_freq_hz < 1000))
+		t->bus_freq_hz = 1000;
+
+	/*
+	 * min_low_ns: The minimum number of ns we need to hold low to
+	 *	       meet I2C specification, should include fall time.
+	 * min_high_ns: The minimum number of ns we need to hold high to
+	 *	        meet I2C specification, should include rise time.
+	 */
+	spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+
+	/* calculate min-divh and min-divl */
+	clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
+	scl_rate_khz = t->bus_freq_hz / 1000;
+	min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
+
+	min_high_ns = t->scl_rise_ns + spec->min_high_ns;
+	min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
+
+	min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+	min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
+
+	/*
+	 * Final divh and divl must be greater than 0, otherwise the
+	 * hardware would not output the i2c clk.
+	 */
+	min_high_div = (min_high_div < 1) ? 2 : min_high_div;
+	min_low_div = (min_low_div < 1) ? 2 : min_low_div;
+
+	/* These are the min dividers needed for min hold times. */
+	min_div_for_hold = (min_low_div + min_high_div);
+	min_total_ns = min_low_ns + min_high_ns;
+
+	/*
+	 * This is the maximum divider so we don't go over the maximum.
+	 * We don't round up here (we round down) since this is a maximum.
+	 */
+	 if (min_div_for_hold >= min_total_div) {
+		/*
+		 * Time needed to meet hold requirements is important.
+		 * Just use that.
+		 */
+		t_calc->div_low = min_low_div;
+		t_calc->div_high = min_high_div;
+	} else {
+		/*
+		 * We've got to distribute some time among the low and high
+		 * so we don't run too fast.
+		 * We'll try to split things up by the scale of min_low_div and
+		 * min_high_div, biasing slightly towards having a higher div
+		 * for low (spend more time low).
+		 */
+		extra_div = min_total_div - min_div_for_hold;
+		extra_low_div = DIV_ROUND_UP(min_low_div * extra_div,
+					     min_div_for_hold);
+
+		t_calc->div_low = min_low_div + extra_low_div;
+		t_calc->div_high = min_high_div + (extra_div - extra_low_div);
+	}
+
+	/*
+	 * calculate sda data hold count by the rules, data_upd_st:3
+	 * is a appropriate value to reduce calculated times.
+	 */
+	for (sda_update_cfg = 3; sda_update_cfg > 0; sda_update_cfg--) {
+		max_hold_data_ns =  DIV_ROUND_UP((sda_update_cfg
+						 * (t_calc->div_low) + 1)
+						 * 1000000, clk_rate_khz);
+		min_setup_data_ns =  DIV_ROUND_UP(((8 - sda_update_cfg)
+						 * (t_calc->div_low) + 1)
+						 * 1000000, clk_rate_khz);
+		if ((max_hold_data_ns < spec->max_data_hold_ns) &&
+		    (min_setup_data_ns > spec->min_data_setup_ns))
+			break;
+	}
+
+	/* calculate setup start config */
+	min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns;
+	stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns
+			   - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+	/* calculate setup stop config */
+	min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns;
+	stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns
+			   - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+	t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) |
+			 REG_CON_STA_CFG(--stp_sta_cfg) |
+			 REG_CON_STO_CFG(--stp_sto_cfg);
+
+	t_calc->div_low--;
+	t_calc->div_high--;
+
+	/* Maximum divider supported by hw is 0xffff */
+	if (t_calc->div_low > 0xffff) {
+		t_calc->div_low = 0xffff;
+		ret = -EINVAL;
+	}
+
+	if (t_calc->div_high > 0xffff) {
+		t_calc->div_high = 0xffff;
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 {
 	struct i2c_timings *t = &i2c->t;
 	struct rk3x_i2c_calced_timings calc;
 	u64 t_low_ns, t_high_ns;
+	unsigned long flags;
+	u32 val;
 	int ret;
 
-	ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
+	ret = i2c->soc_data->calc_timings(clk_rate, t, &calc);
 	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
 
-	clk_enable(i2c->clk);
+	clk_enable(i2c->pclk);
+
+	spin_lock_irqsave(&i2c->lock, flags);
+	val = i2c_readl(i2c, REG_CON);
+	val &= ~REG_CON_TUNING_MASK;
+	val |= calc.tuning;
+	i2c_writel(i2c, val, REG_CON);
 	i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
 		   REG_CLKDIV);
-	clk_disable(i2c->clk);
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	clk_disable(i2c->pclk);
 
 	t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
 	t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
@@ -712,7 +916,13 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
-		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0)
+		/*
+		 * Try the calculation (but don't store the result) ahead of
+		 * time to see if we need to block the clock change.  Timings
+		 * shouldn't actually take effect until rk3x_i2c_adapt_div().
+		 */
+		if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t,
+						&calc) != 0)
 			return NOTIFY_STOP;
 
 		/* scale up */
@@ -822,12 +1032,14 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 {
 	struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
 	unsigned long timeout, flags;
+	u32 val;
 	int ret = 0;
 	int i;
 
 	spin_lock_irqsave(&i2c->lock, flags);
 
 	clk_enable(i2c->clk);
+	clk_enable(i2c->pclk);
 
 	i2c->is_last_msg = false;
 
@@ -861,7 +1073,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 
 			/* Force a STOP condition without interrupt */
 			i2c_writel(i2c, 0, REG_IEN);
-			i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON);
+			val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+			val |= REG_CON_EN | REG_CON_STOP;
+			i2c_writel(i2c, val, REG_CON);
 
 			i2c->state = STATE_IDLE;
 
@@ -875,7 +1089,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 		}
 	}
 
+	clk_disable(i2c->pclk);
 	clk_disable(i2c->clk);
+
 	spin_unlock_irqrestore(&i2c->lock, flags);
 
 	return ret < 0 ? ret : num;
@@ -893,18 +1109,27 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
 
 static const struct rk3x_i2c_soc_data rk3066_soc_data = {
 	.grf_offset = 0x154,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3188_soc_data = {
 	.grf_offset = 0x0a4,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3228_soc_data = {
 	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3288_soc_data = {
 	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3399_soc_data = {
+	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v1_calc_timings,
 };
 
 static const struct of_device_id rk3x_i2c_match[] = {
@@ -924,6 +1149,10 @@ static const struct of_device_id rk3x_i2c_match[] = {
 		.compatible = "rockchip,rk3288-i2c",
 		.data = (void *)&rk3288_soc_data
 	},
+	{
+		.compatible = "rockchip,rk3399-i2c",
+		.data = (void *)&rk3399_soc_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
@@ -963,12 +1192,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 	spin_lock_init(&i2c->lock);
 	init_waitqueue_head(&i2c->wait);
 
-	i2c->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(i2c->clk)) {
-		dev_err(&pdev->dev, "cannot get clock\n");
-		return PTR_ERR(i2c->clk);
-	}
-
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(i2c->regs))
@@ -1022,17 +1245,44 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, i2c);
 
+	if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) {
+		/* Only one clock to use for bus clock and peripheral clock */
+		i2c->clk = devm_clk_get(&pdev->dev, NULL);
+		i2c->pclk = i2c->clk;
+	} else {
+		i2c->clk = devm_clk_get(&pdev->dev, "i2c");
+		i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
+	}
+
+	if (IS_ERR(i2c->clk)) {
+		ret = PTR_ERR(i2c->clk);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret);
+		return ret;
+	}
+	if (IS_ERR(i2c->pclk)) {
+		ret = PTR_ERR(i2c->pclk);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret);
+		return ret;
+	}
+
 	ret = clk_prepare(i2c->clk);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "Could not prepare clock\n");
+		dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret);
 		return ret;
 	}
+	ret = clk_prepare(i2c->pclk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret);
+		goto err_clk;
+	}
 
 	i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
 	ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "Unable to register clock notifier\n");
-		goto err_clk;
+		goto err_pclk;
 	}
 
 	clk_rate = clk_get_rate(i2c->clk);
@@ -1050,6 +1300,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 
 err_clk_notifier:
 	clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+err_pclk:
+	clk_unprepare(i2c->pclk);
 err_clk:
 	clk_unprepare(i2c->clk);
 	return ret;
@@ -1062,6 +1314,7 @@ static int rk3x_i2c_remove(struct platform_device *pdev)
 	i2c_del_adapter(&i2c->adap);
 
 	clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+	clk_unprepare(i2c->pclk);
 	clk_unprepare(i2c->clk);
 
 	return 0;
-- 
1.9.1




From david.wu at rock-chips.com  Thu May 12 01:01:15 2016
From: david.wu at rock-chips.com (David Wu)
Date: Thu, 12 May 2016 16:01:15 +0800
Subject: [PATCH v9 8/8] i2c: rk3x: support fast-mode plus for rk3399
In-Reply-To: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
References: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463040075-8438-1-git-send-email-david.wu@rock-chips.com>

Implement fast mode plus that allows bus speeds of up to 1MHz.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
Tested-by: Caesar Wang <wxt at rock-chips.com>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v9:
- add commit message

Change in v8:
- none

 drivers/i2c/busses/i2c-rk3x.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 673656e..ba4ce39 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -126,6 +126,17 @@ static const struct i2c_spec_values fast_mode_spec = {
 	.min_hold_buffer_ns = 1300,
 };
 
+static const struct i2c_spec_values fast_mode_plus_spec = {
+	.min_hold_start_ns = 260,
+	.min_low_ns = 500,
+	.min_high_ns = 260,
+	.min_setup_start_ns = 260,
+	.max_data_hold_ns = 400,
+	.min_data_setup_ns = 50,
+	.min_setup_stop_ns = 260,
+	.min_hold_buffer_ns = 500,
+};
+
 /**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
@@ -531,8 +542,10 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
 {
 	if (speed <= 100000)
 		return &standard_mode_spec;
-	else
+	else if (speed <= 400000)
 		return &fast_mode_spec;
+	else
+		return &fast_mode_plus_spec;
 }
 
 /**
@@ -743,9 +756,9 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
 	const struct i2c_spec_values *spec;
 	int ret = 0;
 
-	/* Support standard-mode and fast-mode */
-	if (WARN_ON(t->bus_freq_hz > 400000))
-		t->bus_freq_hz = 400000;
+	/* Support standard-mode, fast-mode and fast-mode plus */
+	if (WARN_ON(t->bus_freq_hz > 1000000))
+		t->bus_freq_hz = 1000000;
 
 	/* prevent scl_rate_khz from becoming 0 */
 	if (WARN_ON(t->bus_freq_hz < 1000))
-- 
1.9.1




From heiko at sntech.de  Thu May 12 01:30:25 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Thu, 12 May 2016 10:30:25 +0200
Subject: [PATCH v8 8/8] i2c: rk3x: support fast-mode plus for rk3399
In-Reply-To: <CAD=FV=VzQ8PRokgAaTV00L31mcXFEzBG8c1NB4+Rqyx75hwwDg@mail.gmail.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <5153288.jNhUuzGC3g@phil>
 <CAD=FV=VzQ8PRokgAaTV00L31mcXFEzBG8c1NB4+Rqyx75hwwDg@mail.gmail.com>
Message-ID: <6806722.VBDbziL6YI@phil>

Am Mittwoch, 11. Mai 2016, 16:41:54 schrieb Doug Anderson:
> Heiko,
> 
> On Wed, May 11, 2016 at 2:09 PM, Heiko Stuebner <heiko at sntech.de> wrote:
> > Additionally, the i2c-noob in me would wish for a short sentence on
> > where
> > the timing values come from (measured, somewhere in the TRM I didn't
> > find or something completely different).
> 
> If you search for "UM10204" you'll find the first link is
> <http://www.nxp.com/documents/user_manual/UM10204.pdf>.  That appears
> to be the official standard.  At least that's what
> <http://www.i2c-bus.org/fast-mode-plus/> says (though they have an old
> link).

I did find that document yesterday, but was to blind and somehow only saw the 
separate table for highspeed-timings. On a closer look, I now also found the 
timing-table for the other modes [due to the bigger font-size used there? 
;-) ]



From david.wu at rock-chips.com  Thu May 12 08:07:34 2016
From: david.wu at rock-chips.com (David.Wu)
Date: Thu, 12 May 2016 23:07:34 +0800
Subject: [PATCH v8 7/8] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <5733D7AA.1060500@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908698-27284-1-git-send-email-david.wu@rock-chips.com>
 <CAD=FV=Uf-U3RBpgFbR3LkPAJTWqz3d02+H7iyA-SS-y=r3cXjA@mail.gmail.com>
 <5733D7AA.1060500@rock-chips.com>
Message-ID: <57349C36.4030401@rock-chips.com>

Hi Doug?

? 2016/5/12 9:08, David.Wu ??:
> Hi Doug,
>
> ? 2016/5/12 1:37, Doug Anderson ??:
>> Hi,
>>
>> On Tue, May 10, 2016 at 12:31 PM, David Wu <david.wu at rock-chips.com>
>> wrote:
>>>   static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long
>>> clk_rate)
>>>   {
>>>          struct i2c_timings *t = &i2c->t;
>>>          struct rk3x_i2c_calced_timings calc;
>>>          u64 t_low_ns, t_high_ns;
>>> +       u32 val;
>>>          int ret;
>>>
>>> -       ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
>>> +       ret = i2c->soc_data->calc_timings(clk_rate, t, &calc);
>>>          WARN_ONCE(ret != 0, "Could not reach SCL freq %u",
>>> t->bus_freq_hz);
>>>
>>> -       clk_enable(i2c->clk);
>>> +       clk_enable(i2c->pclk);
>>> +
>>>          i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low &
>>> 0xffff),
>>>                     REG_CLKDIV);
>>> -       clk_disable(i2c->clk);
>>> +
>>> +       val = i2c_readl(i2c, REG_CON);
>>> +       val &= ~REG_CON_TUNING_MASK;
>>> +       val |= calc.tuning;
>>> +       i2c_writel(i2c, val, REG_CON);
>>
>> Another subtle bug here.  You need to be holding the spinlock here
>> since you're doing a read-modify-write of a register that is also
>> touched by the interrupt handler.  We never needed it before because
>> the previous register update wasn't touched by anyone else and it was
>> a single atomic write.
>>
>> Also: technically if we are midway through a transfer when all this
>> happens then there will be a very short period of time when the two
>> timing-related registers won't match with each other.  I have no idea
>> how much that would matter, but in the very least it seems wise to
>> minimize the time where they mismatch.  So I'd probably write:
>>
>>         spin_lock_irqsave(&i2c->lock, flags);
>>         val = i2c_readl(i2c, REG_CON);
>>         val &= ~REG_CON_TUNING_MASK;
>>         val |= calc.tuning;
>>         i2c_writel(i2c, val, REG_CON);
>>         i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
>>                    REG_CLKDIV);
>>         spin_unlock_irqrestore(&i2c->lock, flags);
>>
>> ...if we really end up with on a system with a dynamically changing
>> clock that uses the new-style timing and we see real problems, we can
>> always try to come up with a way to avoid any problems.  Sound OK?
>>
>>
>
> Good, add spin_lock is very necessary for atomic write here, thanks for
> your advice.

I also found a subtle bug, it would clean the con register by use 
"i2c_writel(i2c, 0, REG_CON)" in rk3x_i2c_stop(). So i think it would be 
fixed by using read-modify-write way here in next version.

>
>> Otherwise, I think things look good to me.  Caesar's comments would
>> also be good to fix.
>>
>>
>> -Doug
>>
>>
>>



From dianders at chromium.org  Thu May 12 11:03:16 2016
From: dianders at chromium.org (Douglas Anderson)
Date: Thu, 12 May 2016 11:03:16 -0700
Subject: [PATCH 1/2] Revert "clk: rockchip: reset init state before mmc card
 initialization"
Message-ID: <1463076197-15900-1-git-send-email-dianders@chromium.org>

This reverts commit 7a03fe6f48f3 ("clk: rockchip: reset init state
before mmc card initialization").

Though not totally obvious from the commit message nor from the source
code, that commit appears to be trying to reset the "_drv" MMC clocks to
90 degrees (note that the "_sample" MMC clocks have a shift of 0 so are
not touched).

The major problem here is that it doesn't properly reset things.  The
phase is a two bit field and the commit only touches one of the two
bits.  Thus the commit had the following affect:
- phase   0  => phase  90
- phase  90  => phase  90
- phase 180  => phase 270
- phase 270  => phase 270

Things get even weirder if you happen to have a bootloader that was
actually using delay elements (should be no reason to, but you never
know), since those are additional bits that weren't touched by the
original patch.

This is unlikely to be what we actually want.  Checking on rk3288-veyron
devices, I can see that the bootloader leaves these clocks as:
- emmc:  phase 180
- sdmmc: phase 90
- sdio0: phase 90

Thus on rk3288-veyron devices the commit we're reverting had the effect
of changing the eMMC clock to phase 270.  This probably explains the
scattered reports I've heard of eMMC devices not working on some veyron
devices when using the upstream kernel.

The original commit was presumably made because previously the kernel
didn't touch the "_drv" phase at all and relied on whatever value was
there when the kernel started.  If someone was using a bootloader that
touched the "_drv" phase then, indeed, we should have code in the kernel
to fix that.  ...and also, to get ideal timings, we should also have the
kernel change the phase depending on the speed mode.  In fact, that's
the subject of a recent patch I posted at
<https://patchwork.kernel.org/patch/9075141/>.

Ideally, we should take both the patch posted to dw_mmc and this
revert.  Since those will likely go through different trees, here I
describe behavior with the combos:

1. Just this revert: likely will fix rk3288-veyron eMMC on some devices
   + other cases; might break someone with a strange bootloader that
   sets the phase to 0 or one that uses delay elements (pretty
   unpredicable what would happen in that case).
2. Just dw_mmc patch: fixes everyone.  Effectly the dw_mmc patch will
   totally override the broken patch and fix everything.
3. Both patches: fixes everyone.  Once dw_mmc is initting properly then
   any defaults from the clock code doesn't mattery.

Fixes: 7a03fe6f48f3 ("clk: rockchip: reset init state before mmc card initialization")
Signed-off-by: Douglas Anderson <dianders at chromium.org>
---
 drivers/clk/rockchip/clk-mmc-phase.c | 11 -----------
 1 file changed, 11 deletions(-)

diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c
index bc856f21f6b2..5b18265c2306 100644
--- a/drivers/clk/rockchip/clk-mmc-phase.c
+++ b/drivers/clk/rockchip/clk-mmc-phase.c
@@ -41,8 +41,6 @@ static unsigned long rockchip_mmc_recalc(struct clk_hw *hw,
 #define ROCKCHIP_MMC_DEGREE_MASK 0x3
 #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
 #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
-#define ROCKCHIP_MMC_INIT_STATE_RESET 0x1
-#define ROCKCHIP_MMC_INIT_STATE_SHIFT 1
 
 #define PSECS_PER_SEC 1000000000000LL
 
@@ -162,15 +160,6 @@ struct clk *rockchip_clk_register_mmc(const char *name,
 	mmc_clock->reg = reg;
 	mmc_clock->shift = shift;
 
-	/*
-	 * Assert init_state to soft reset the CLKGEN
-	 * for mmc tuning phase and degree
-	 */
-	if (mmc_clock->shift == ROCKCHIP_MMC_INIT_STATE_SHIFT)
-		writel(HIWORD_UPDATE(ROCKCHIP_MMC_INIT_STATE_RESET,
-				     ROCKCHIP_MMC_INIT_STATE_RESET,
-				     mmc_clock->shift), mmc_clock->reg);
-
 	clk = clk_register(NULL, &mmc_clock->hw);
 	if (IS_ERR(clk))
 		kfree(mmc_clock);
-- 
2.8.0.rc3.226.g39d4020



From dianders at chromium.org  Thu May 12 11:03:17 2016
From: dianders at chromium.org (Douglas Anderson)
Date: Thu, 12 May 2016 11:03:17 -0700
Subject: [PATCH 2/2] clk: rockchip: fix the rk3399 sdmmc sample shift
In-Reply-To: <1463076197-15900-1-git-send-email-dianders@chromium.org>
References: <1463076197-15900-1-git-send-email-dianders@chromium.org>
Message-ID: <1463076197-15900-2-git-send-email-dianders@chromium.org>

Just like every other Rockhip device, the MMC "_sample" clocks should
have a shift of 0, not a shift of 1.  The rk3399 TRM agrees.  Presumably
these values were set to 0 because of a typo.

Things _sorta_ would have worked with the incorrect sample phase shift
because of the register layout but wouldn't have been ideal and we would
have skipped lots of phases.  Also: we would never actually enabled the
fine delay unless we happened to have 128 or more delay elements.

This is expected behavior before this patch:
* Try to set:     0 degrees +   1 delay elements
  Actually get:   0 degrees +   0 delay elements
* Try to set:    90 degrees +   0 delay elements
  Actually get: 180 degrees +   0 delay elements
* Try to set:   180 degrees +   0 delay elements
  Actually get:   0 degrees +   0 delay elements
* Try to set:   270 degrees +   0 delay elements
  Actually get: 180 degrees +   0 delay elements
* Try to set:     0 degrees + 129 delay elements
  Actually get:   0 degrees +   2 delay elements
* Try to set:   180 degrees + 129 delay elements
  Actually get:   0 degrees +   3 delay elements
* Try to set:     0 degrees + 130 delay elements
  Actually get:   0 degrees +   4 delay elements

I verified that old code had a problem by turning on debug printouts and
seeing that the old code would report this for one SD card I had:
  Good phase range 347-101 (115 len)
  Good phase range 202-326 (125 len)

After my fix, it went down to one big good range for the same card.
This is more expected:
  Good phase range 189-1 (173 len)
  Good phase range 82-85 (4 len)
  Good phase range 166-168 (3 len)

Signed-off-by: Douglas Anderson <dianders at chromium.org>
---
 drivers/clk/rockchip/clk-rk3399.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
index 291543f52caa..14ff3e109e1e 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -895,10 +895,10 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
 			RK3399_CLKGATE_CON(6), 1, GFLAGS),
 
 	MMC(SCLK_SDMMC_DRV,     "sdmmc_drv",    "clk_sdmmc", RK3399_SDMMC_CON0, 1),
-	MMC(SCLK_SDMMC_SAMPLE,  "sdmmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1),
+	MMC(SCLK_SDMMC_SAMPLE,  "sdmmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 0),
 
 	MMC(SCLK_SDIO_DRV,      "sdio_drv",    "clk_sdio",  RK3399_SDIO_CON0,  1),
-	MMC(SCLK_SDIO_SAMPLE,   "sdio_sample", "clk_sdio",  RK3399_SDIO_CON1,  1),
+	MMC(SCLK_SDIO_SAMPLE,   "sdio_sample", "clk_sdio",  RK3399_SDIO_CON1,  0),
 
 	/* pcie */
 	COMPOSITE(SCLK_PCIE_PM, "clk_pcie_pm", mux_pll_src_cpll_gpll_npll_24m_p, 0,
-- 
2.8.0.rc3.226.g39d4020



From dianders at chromium.org  Thu May 12 11:15:52 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 12 May 2016 11:15:52 -0700
Subject: [PATCH v2] mmc: dw_mmc: rockchip: Set the drive phase properly
In-Reply-To: <1463002848-580-1-git-send-email-dianders@chromium.org>
References: <1463002848-580-1-git-send-email-dianders@chromium.org>
Message-ID: <CAD=FV=UiPo5EnsX+erm5PDsuCHczr1qbhwz8s4FcLeNGPdVuGQ@mail.gmail.com>

Hi,

On Wed, May 11, 2016 at 2:40 PM, Douglas Anderson <dianders at chromium.org> wrote:
> Historically for Rockchip devices we've relied on the power-on
> default (or perhaps the firmware setting) to get the correct drive
> phase for dw_mmc devices.  This worked OK for the most part, but:
>
> * Relying on the setting just "being right" is a bit fragile.
>
> * As soon as there is an instance where the power on default is wrong or
>   where the firmware didn't configure this properly then we'll get a
>   mysterious failure.
>
> Let's explicitly set this phase in the kernel.
>
> The comments inside this patch try to explain the situation quite
> throughly, but the high level overview of this is:
>
> Before this patch on rk3288 devices tested:
> * eMMC: 180 degrees
> * SDMMC/SDIO0/SDIO1: 90 degrees
>
> After this patch:
> * Use 90 degree phase offset usually.
> * Use 180 degree phase offset for MMC_DDR52, SDR104, HS200.
>
> That means we are _changing_ behavior for those devices in this way:
>
> * If we have HS200 eMMC or DDR52 eMMC, we'll run ID mode at 90
>   degrees (vs 180) but otherwise have no change.
>
> * For any non-HS200 / non-DDR52 eMMC devices we'll now _always_ run at
>   90 degrees (vs 180).  It seems fairly unlikely that building modern
>   hardware is using an eMMC that isn't using DDR52 or HS200, of course.
>
> * For SDR104 cards we'll now run with 180 degree phase offset (vs 90).
>   It's expected that 90 degree phase offset would have worked OK, but
>   this gives us extra margin.
>
> I have tested this by inserting my collection of uSD cards (mostly UHS,
> though a few not) into a veyron_minnie and confirmed that they still
> seem to enumerate properly.  For a subset of them I tried putting a
> filesystem on them and also tried running mmc_test.
>
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> ---
> Changes in v2:
> - Now use 90 degrees for some modes; updated comments to say why.
>
>  drivers/mmc/host/dw_mmc-rockchip.c | 64 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 64 insertions(+)

Just a note that I have since found out that recent patches in the
kernel in fact _do_ init the drive phase and apparently do it
improperly.  That means that $SUBJECT patch actually is expected to
fix real problems on real devices.

See <https://patchwork.kernel.org/patch/9085311/> for some details.

-Doug


From dianders at chromium.org  Thu May 12 11:31:50 2016
From: dianders at chromium.org (Douglas Anderson)
Date: Thu, 12 May 2016 11:31:50 -0700
Subject: [PATCH v3] mmc: dw_mmc: rockchip: Set the drive phase properly
Message-ID: <1463077910-25914-1-git-send-email-dianders@chromium.org>

Historically for Rockchip devices we've relied on the power-on
default (or perhaps the firmware setting) to get the correct drive
phase for dw_mmc devices.  This worked OK for the most part, but:

* Relying on the setting just "being right" is a bit fragile.

* As soon as there is an instance where the power on default is wrong or
  where the firmware didn't configure this properly then we'll get a
  mysterious failure.

In commit 7a03fe6f48f3 ("clk: rockchip: reset init state before mmc card
initialization") we actually started setting this explicitly in the
kernel, but that commit wasn't quite right and also wasn't quite
enough.  See <https://patchwork.kernel.org/patch/9085311/> for some
details.

Let's explicitly set this phase in dw_mmc.

The comments inside this patch try to explain the situation quite
throughly, but the high level overview of this is:

Before this patch on rk3288 devices tested (after revert of the clock
patch described above):
* eMMC: 180 degrees
* SDMMC/SDIO0/SDIO1: 90 degrees

After this patch:
* Use 90 degree phase offset usually.
* Use 180 degree phase offset for MMC_DDR52, SDR104, HS200.

That means we are _changing_ behavior for those devices in this way:

* If we have HS200 eMMC or DDR52 eMMC, we'll run ID mode at 90
  degrees (vs 180) but otherwise have no change.

* For any non-HS200 / non-DDR52 eMMC devices we'll now _always_ run at
  90 degrees (vs 180).  It seems fairly unlikely that building modern
  hardware is using an eMMC that isn't using DDR52 or HS200, of course.

* For SDR104 cards we'll now run with 180 degree phase offset (vs 90).
  It's expected that 90 degree phase offset would have worked OK, but
  this gives us extra margin.

I have tested this by inserting my collection of uSD cards (mostly UHS,
though a few not) into a veyron_minnie and confirmed that they still
seem to enumerate properly.  For a subset of them I tried putting a
filesystem on them and also tried running mmc_test.

Fixes: 7a03fe6f48f3 ("clk: rockchip: reset init state before mmc card initialization")
Signed-off-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>
---
Changes in v3:
- Fixed minor typo; point that this really fixes something in desc.
- Add Shawn's Reviewed-by

Changes in v2:
- Now use 90 degrees for some modes; updated comments to say why.

 drivers/mmc/host/dw_mmc-rockchip.c | 64 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index 8c20b81cafd8..b9e4fe5a2393 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -66,6 +66,70 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
 	/* Make sure we use phases which we can enumerate with */
 	if (!IS_ERR(priv->sample_clk))
 		clk_set_phase(priv->sample_clk, priv->default_sample_phase);
+
+	/*
+	 * Set the drive phase offset based on speed mode to achieve hold times.
+	 *
+	 * NOTE: this is _not_ a value that is dynamically tuned and is also
+	 * _not_ a value that will vary from board to board.  It is a value
+	 * that could vary between different SoC models if they had massively
+	 * different output clock delays inside their dw_mmc IP block (delay_o),
+	 * but since it's OK to overshoot a little we don't need to do complex
+	 * calculations and can pick values that will just work for everyone.
+	 *
+	 * When picking values we'll stick with picking 0/90/180/270 since
+	 * those can be made very accurately on all known Rockchip SoCs.
+	 *
+	 * Note that these values match values from the DesignWare Databook
+	 * tables for the most part except for SDR12 and "ID mode".  For those
+	 * two modes the databook calculations assume a clock in of 50MHz.  As
+	 * seen above, we always use a clock in rate that is exactly the
+	 * card's input clock (times RK3288_CLKGEN_DIV, but that gets divided
+	 * back out before the controller sees it).
+	 *
+	 * From measurement of a single device, it appears that delay_o is
+	 * about .5 ns.  Since we try to leave a bit of margin, it's expected
+	 * that numbers here will be fine even with much larger delay_o
+	 * (the 1.4 ns assumed by the DesignWare Databook would result in the
+	 * same results, for instance).
+	 */
+	if (!IS_ERR(priv->drv_clk)) {
+		int phase;
+
+		/*
+		 * In almost all cases a 90 degree phase offset will provide
+		 * sufficient hold times across all valid input clock rates
+		 * assuming delay_o is not absurd for a given SoC.  We'll use
+		 * that as a default.
+		 */
+		phase = 90;
+
+		switch (ios->timing) {
+		case MMC_TIMING_MMC_DDR52:
+			/*
+			 * Since clock in rate with MMC_DDR52 is doubled when
+			 * bus width is 8 we need to double the phase offset
+			 * to get the same timings.
+			 */
+			if (ios->bus_width == MMC_BUS_WIDTH_8)
+				phase = 180;
+			break;
+		case MMC_TIMING_UHS_SDR104:
+		case MMC_TIMING_MMC_HS200:
+			/*
+			 * In the case of 150 MHz clock (typical max for
+			 * Rockchip SoCs), 90 degree offset will add a delay
+			 * of 1.67 ns.  That will meet min hold time of .8 ns
+			 * as long as clock output delay is < .87 ns.  On
+			 * SoCs measured this seems to be OK, but it doesn't
+			 * hurt to give margin here, so we use 180.
+			 */
+			phase = 180;
+			break;
+		}
+
+		clk_set_phase(priv->drv_clk, phase);
+	}
 }
 
 #define NUM_PHASES			360
-- 
2.8.0.rc3.226.g39d4020



From dianders at chromium.org  Thu May 12 14:09:24 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 12 May 2016 14:09:24 -0700
Subject: [PATCH v8 7/8] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <57349C36.4030401@rock-chips.com>
References: <1462908252-27016-1-git-send-email-david.wu@rock-chips.com>
 <1462908698-27284-1-git-send-email-david.wu@rock-chips.com>
 <CAD=FV=Uf-U3RBpgFbR3LkPAJTWqz3d02+H7iyA-SS-y=r3cXjA@mail.gmail.com>
 <5733D7AA.1060500@rock-chips.com> <57349C36.4030401@rock-chips.com>
Message-ID: <CAD=FV=W1-DDtuLUzW1uLiFxuhpnmhnKB1od_yweY=WJ-4u3=kQ@mail.gmail.com>

David,

On Thu, May 12, 2016 at 8:07 AM, David.Wu <david.wu at rock-chips.com> wrote:
> I also found a subtle bug, it would clean the con register by use
> "i2c_writel(i2c, 0, REG_CON)" in rk3x_i2c_stop(). So i think it would be
> fixed by using read-modify-write way here in next version.

Good catch.  I look forward to the next version (maybe the last
version, since this series is looking really good).

-Doug


From briannorris at chromium.org  Thu May 12 15:22:23 2016
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 May 2016 15:22:23 -0700
Subject: [PATCH 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
In-Reply-To: <3e257ce2-056a-592a-9481-970da1fe0627@rock-chips.com>
References: <1462924975-69072-1-git-send-email-briannorris@chromium.org>
 <3e257ce2-056a-592a-9481-970da1fe0627@rock-chips.com>
Message-ID: <20160512222223.GA57835@google.com>

On Wed, May 11, 2016 at 09:17:38AM +0800, Shawn Lin wrote:
> How about adding these?
> 
> assigned-clocks = <&cru SCLK_EMMC>;
> assigned-clock-parents = <&cru PLL_CPLL>; //may not need

BTW, even if I assign the parent here, it's not actually taking effect
on my system. Presumably the common clock framework is finding a
"better" way to satisfy 200 MHz through GPLL instead. So I'm dropping
the assigned-clock-parents for v2.

> assigned-clock-rates = <200000000>;

Brian


From briannorris at chromium.org  Thu May 12 15:35:51 2016
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 May 2016 15:35:51 -0700
Subject: [PATCH v2 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
Message-ID: <1463092552-60696-1-git-send-email-briannorris@chromium.org>

Add description for the SDHCI v5.1 eMMC controller on rk3399. Fix it to
200 MHz, to support all supported timing modes.

Note that 'rockchip,rk3399-sdhci-5.1' is not documented; we presumably
have a compliant Arasan controller, but let's have a rockchip property
as the canonical backup/precautionary measure. Per Heiko's previous
suggestion, let's not clutter the arasan doc with it.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
v2:

 * improved commit message
 * assign eMMC clock to 200 MHz

 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a143b0..9980c2eab4e9 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -215,6 +215,19 @@
 		status = "disabled";
 	};
 
+	sdhci: sdhci at fe330000 {
+		compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
+		reg = <0x0 0xfe330000 0x0 0x10000>;
+		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
+		clock-names = "clk_xin", "clk_ahb";
+		assigned-clocks = <&cru SCLK_EMMC>;
+		assigned-clock-rates = <200000000>;
+		phys = <&emmc_phy>;
+		phy-names = "phy_arasan";
+		status = "disabled";
+	};
+
 	usb_host0_ehci: usb at fe380000 {
 		compatible = "generic-ehci";
 		reg = <0x0 0xfe380000 0x0 0x20000>;
@@ -481,8 +494,18 @@
 	};
 
 	grf: syscon at ff770000 {
-		compatible = "rockchip,rk3399-grf", "syscon";
+		compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
 		reg = <0x0 0xff770000 0x0 0x10000>;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		emmc_phy: phy at f780 {
+			compatible = "rockchip,rk3399-emmc-phy";
+			reg = <0xf780 0x20>;
+			#phy-cells = <0>;
+			status = "disabled";
+		};
 	};
 
 	watchdog at ff840000 {
-- 
2.8.0.rc3.226.g39d4020



From briannorris at chromium.org  Thu May 12 15:35:52 2016
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 May 2016 15:35:52 -0700
Subject: [PATCH v2 2/2] ARM64: dts: rockchip: enable eMMC for rk3399 EVB
In-Reply-To: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
References: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
Message-ID: <1463092552-60696-2-git-send-email-briannorris@chromium.org>

Rockchip's rk3399 evaluation board has eMMC. Let's enable the
newly-added node.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
v2:

 * better commit description

 arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
index 1a3eb1482050..0b27d91084c4 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
@@ -89,6 +89,18 @@
 	status = "okay";
 };
 
+&emmc_phy {
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	non-removable;
+	status = "okay";
+};
+
 &uart2 {
 	status = "okay";
 };
-- 
2.8.0.rc3.226.g39d4020



From briannorris at chromium.org  Thu May 12 15:43:03 2016
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 May 2016 15:43:03 -0700
Subject: [PATCH 1/4] phy: rockchip-emmc: give DLL some extra time to be ready
Message-ID: <1463092986-61777-1-git-send-email-briannorris@chromium.org>

From: Shawn Lin <shawn.lin at rock-chips.com>

According to the databook, 10.2us is the max time for dll to be ready to
work. However in testing, some chips need 20us for dll to be ready. This
patch adds some extra margin for dllrdy to be ready, fixing our
-ETIMEDOUT issues.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 drivers/phy/phy-rockchip-emmc.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/phy/phy-rockchip-emmc.c b/drivers/phy/phy-rockchip-emmc.c
index 6ebcf3e41c46..48cbe691a889 100644
--- a/drivers/phy/phy-rockchip-emmc.c
+++ b/drivers/phy/phy-rockchip-emmc.c
@@ -119,10 +119,11 @@ static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
 				   PHYCTRL_ENDLL_MASK,
 				   PHYCTRL_ENDLL_SHIFT));
 	/*
-	 * After enable analog DLL circuits, we need extra 10.2us
-	 * for dll to be ready for work.
+	 * After enable analog DLL circuits, we need an extra 10.2us
+	 * for dll to be ready for work. But according to testing, we
+	 * find some chips need more than 25us.
 	 */
-	udelay(11);
+	udelay(30);
 	regmap_read(rk_phy->reg_base,
 		    rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
 		    &dllrdy);
-- 
2.8.0.rc3.226.g39d4020



From briannorris at chromium.org  Thu May 12 15:43:04 2016
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 May 2016 15:43:04 -0700
Subject: [PATCH 2/4] phy: rockchip-emmc: configure frequency range and drive
 impedance
In-Reply-To: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
Message-ID: <1463092986-61777-2-git-send-email-briannorris@chromium.org>

From: Shawn Lin <shawn.lin at rock-chips.com>

Signal integrity analysis has suggested we set these values. Do this in
power_on(), so that they get reconfigured after suspend/resume.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 drivers/phy/phy-rockchip-emmc.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/phy/phy-rockchip-emmc.c b/drivers/phy/phy-rockchip-emmc.c
index 48cbe691a889..5641dede32f6 100644
--- a/drivers/phy/phy-rockchip-emmc.c
+++ b/drivers/phy/phy-rockchip-emmc.c
@@ -56,6 +56,19 @@
 #define PHYCTRL_DLLRDY_SHIFT	0x5
 #define PHYCTRL_DLLRDY_DONE	0x1
 #define PHYCTRL_DLLRDY_GOING	0x0
+#define PHYCTRL_FREQSEL_200M	0x0
+#define PHYCTRL_FREQSEL_50M	0x1
+#define PHYCTRL_FREQSEL_100M	0x2
+#define PHYCTRL_FREQSEL_150M	0x3
+#define PHYCTRL_FREQSEL_MASK	0x3
+#define PHYCTRL_FREQSEL_SHIFT	0xc
+#define PHYCTRL_DR_MASK		0x7
+#define PHYCTRL_DR_SHIFT	0x4
+#define PHYCTRL_DR_50OHM	0x0
+#define PHYCTRL_DR_33OHM	0x1
+#define PHYCTRL_DR_66OHM	0x2
+#define PHYCTRL_DR_100OHM	0x3
+#define PHYCTRL_DR_40OHM	0x4
 
 struct rockchip_emmc_phy {
 	unsigned int	reg_offset;
@@ -154,6 +167,20 @@ static int rockchip_emmc_phy_power_on(struct phy *phy)
 	struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
 	int ret = 0;
 
+	/* DLL operation: 170 to 200 MHz */
+	regmap_write(rk_phy->reg_base,
+		     rk_phy->reg_offset + GRF_EMMCPHY_CON0,
+		     HIWORD_UPDATE(PHYCTRL_FREQSEL_200M,
+				   PHYCTRL_FREQSEL_MASK,
+				   PHYCTRL_FREQSEL_SHIFT));
+
+	/* Drive impedance: 50 Ohm */
+	regmap_write(rk_phy->reg_base,
+		     rk_phy->reg_offset + GRF_EMMCPHY_CON6,
+		     HIWORD_UPDATE(PHYCTRL_DR_50OHM,
+				   PHYCTRL_DR_MASK,
+				   PHYCTRL_DR_SHIFT));
+
 	/* Power up emmc phy analog blocks */
 	ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_ON);
 	if (ret)
-- 
2.8.0.rc3.226.g39d4020



From briannorris at chromium.org  Thu May 12 15:43:05 2016
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 May 2016 15:43:05 -0700
Subject: [PATCH 3/4] phy: rockchip-emmc: configure default output tap delay
In-Reply-To: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
Message-ID: <1463092986-61777-3-git-send-email-briannorris@chromium.org>

The output tap delay controls helps maintain the hold requirements for
eMMC. The exact value is dependent on the SoC and other factors, though
it isn't really an exact science. But the default of 0 is not very good,
as it doesn't give the eMMC much hold time, so let's bump up to 4
(approx 90 degree phase?). If we need to configure this any further
(e.g., based on board or speed factors), we may need to consider a
device tree representation.

Suggested-by: Shawn Lin <shawn.lin at rock-chips.com>
Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 drivers/phy/phy-rockchip-emmc.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/phy/phy-rockchip-emmc.c b/drivers/phy/phy-rockchip-emmc.c
index 5641dede32f6..f94d3a6587ed 100644
--- a/drivers/phy/phy-rockchip-emmc.c
+++ b/drivers/phy/phy-rockchip-emmc.c
@@ -69,6 +69,11 @@
 #define PHYCTRL_DR_66OHM	0x2
 #define PHYCTRL_DR_100OHM	0x3
 #define PHYCTRL_DR_40OHM	0x4
+#define PHYCTRL_OTAPDLYENA		0x1
+#define PHYCTRL_OTAPDLYENA_MASK		0x1
+#define PHYCTRL_OTAPDLYENA_SHIFT	0xb
+#define PHYCTRL_OTAPDLYSEL_MASK		0xf
+#define PHYCTRL_OTAPDLYSEL_SHIFT	0x7
 
 struct rockchip_emmc_phy {
 	unsigned int	reg_offset;
@@ -181,6 +186,20 @@ static int rockchip_emmc_phy_power_on(struct phy *phy)
 				   PHYCTRL_DR_MASK,
 				   PHYCTRL_DR_SHIFT));
 
+	/* Output tap delay: enable */
+	regmap_write(rk_phy->reg_base,
+		     rk_phy->reg_offset + GRF_EMMCPHY_CON0,
+		     HIWORD_UPDATE(PHYCTRL_OTAPDLYENA,
+				   PHYCTRL_OTAPDLYENA_MASK,
+				   PHYCTRL_OTAPDLYENA_SHIFT));
+
+	/* Output tap delay */
+	regmap_write(rk_phy->reg_base,
+		     rk_phy->reg_offset + GRF_EMMCPHY_CON0,
+		     HIWORD_UPDATE(4,
+				   PHYCTRL_OTAPDLYSEL_MASK,
+				   PHYCTRL_OTAPDLYSEL_SHIFT));
+
 	/* Power up emmc phy analog blocks */
 	ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_ON);
 	if (ret)
-- 
2.8.0.rc3.226.g39d4020



From briannorris at chromium.org  Thu May 12 15:43:06 2016
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 May 2016 15:43:06 -0700
Subject: [PATCH 4/4] phy: rockchip-emmc: reindent the register definitions
In-Reply-To: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
Message-ID: <1463092986-61777-4-git-send-email-briannorris@chromium.org>

Some of the spacing was wrong (spaces instead of tabs), and due to
longer entries added later, the columns weren't aligned. Let's get
everything consistent.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 drivers/phy/phy-rockchip-emmc.c | 76 ++++++++++++++++++++---------------------
 1 file changed, 38 insertions(+), 38 deletions(-)

diff --git a/drivers/phy/phy-rockchip-emmc.c b/drivers/phy/phy-rockchip-emmc.c
index f94d3a6587ed..c27ca2b39dfe 100644
--- a/drivers/phy/phy-rockchip-emmc.c
+++ b/drivers/phy/phy-rockchip-emmc.c
@@ -31,44 +31,44 @@
 		((val) << (shift) | (mask) << ((shift) + 16))
 
 /* Register definition */
-#define GRF_EMMCPHY_CON0	0x0
-#define GRF_EMMCPHY_CON1	0x4
-#define GRF_EMMCPHY_CON2	0x8
-#define GRF_EMMCPHY_CON3	0xc
-#define GRF_EMMCPHY_CON4	0x10
-#define GRF_EMMCPHY_CON5	0x14
-#define GRF_EMMCPHY_CON6	0x18
-#define GRF_EMMCPHY_STATUS	0x20
-
-#define PHYCTRL_PDB_MASK	0x1
-#define PHYCTRL_PDB_SHIFT	0x0
-#define PHYCTRL_PDB_PWR_ON	0x1
-#define PHYCTRL_PDB_PWR_OFF	0x0
-#define PHYCTRL_ENDLL_MASK	0x1
-#define PHYCTRL_ENDLL_SHIFT     0x1
-#define PHYCTRL_ENDLL_ENABLE	0x1
-#define PHYCTRL_ENDLL_DISABLE	0x0
-#define PHYCTRL_CALDONE_MASK	0x1
-#define PHYCTRL_CALDONE_SHIFT   0x6
-#define PHYCTRL_CALDONE_DONE	0x1
-#define PHYCTRL_CALDONE_GOING	0x0
-#define PHYCTRL_DLLRDY_MASK	0x1
-#define PHYCTRL_DLLRDY_SHIFT	0x5
-#define PHYCTRL_DLLRDY_DONE	0x1
-#define PHYCTRL_DLLRDY_GOING	0x0
-#define PHYCTRL_FREQSEL_200M	0x0
-#define PHYCTRL_FREQSEL_50M	0x1
-#define PHYCTRL_FREQSEL_100M	0x2
-#define PHYCTRL_FREQSEL_150M	0x3
-#define PHYCTRL_FREQSEL_MASK	0x3
-#define PHYCTRL_FREQSEL_SHIFT	0xc
-#define PHYCTRL_DR_MASK		0x7
-#define PHYCTRL_DR_SHIFT	0x4
-#define PHYCTRL_DR_50OHM	0x0
-#define PHYCTRL_DR_33OHM	0x1
-#define PHYCTRL_DR_66OHM	0x2
-#define PHYCTRL_DR_100OHM	0x3
-#define PHYCTRL_DR_40OHM	0x4
+#define GRF_EMMCPHY_CON0		0x0
+#define GRF_EMMCPHY_CON1		0x4
+#define GRF_EMMCPHY_CON2		0x8
+#define GRF_EMMCPHY_CON3		0xc
+#define GRF_EMMCPHY_CON4		0x10
+#define GRF_EMMCPHY_CON5		0x14
+#define GRF_EMMCPHY_CON6		0x18
+#define GRF_EMMCPHY_STATUS		0x20
+
+#define PHYCTRL_PDB_MASK		0x1
+#define PHYCTRL_PDB_SHIFT		0x0
+#define PHYCTRL_PDB_PWR_ON		0x1
+#define PHYCTRL_PDB_PWR_OFF		0x0
+#define PHYCTRL_ENDLL_MASK		0x1
+#define PHYCTRL_ENDLL_SHIFT		0x1
+#define PHYCTRL_ENDLL_ENABLE		0x1
+#define PHYCTRL_ENDLL_DISABLE		0x0
+#define PHYCTRL_CALDONE_MASK		0x1
+#define PHYCTRL_CALDONE_SHIFT		0x6
+#define PHYCTRL_CALDONE_DONE		0x1
+#define PHYCTRL_CALDONE_GOING		0x0
+#define PHYCTRL_DLLRDY_MASK		0x1
+#define PHYCTRL_DLLRDY_SHIFT		0x5
+#define PHYCTRL_DLLRDY_DONE		0x1
+#define PHYCTRL_DLLRDY_GOING		0x0
+#define PHYCTRL_FREQSEL_200M		0x0
+#define PHYCTRL_FREQSEL_50M		0x1
+#define PHYCTRL_FREQSEL_100M		0x2
+#define PHYCTRL_FREQSEL_150M		0x3
+#define PHYCTRL_FREQSEL_MASK		0x3
+#define PHYCTRL_FREQSEL_SHIFT		0xc
+#define PHYCTRL_DR_MASK			0x7
+#define PHYCTRL_DR_SHIFT		0x4
+#define PHYCTRL_DR_50OHM		0x0
+#define PHYCTRL_DR_33OHM		0x1
+#define PHYCTRL_DR_66OHM		0x2
+#define PHYCTRL_DR_100OHM		0x3
+#define PHYCTRL_DR_40OHM		0x4
 #define PHYCTRL_OTAPDLYENA		0x1
 #define PHYCTRL_OTAPDLYENA_MASK		0x1
 #define PHYCTRL_OTAPDLYENA_SHIFT	0xb
-- 
2.8.0.rc3.226.g39d4020



From heiko at sntech.de  Thu May 12 15:52:51 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 13 May 2016 00:52:51 +0200
Subject: [PATCH v3] mmc: dw_mmc: rockchip: Set the drive phase properly
In-Reply-To: <1463077910-25914-1-git-send-email-dianders@chromium.org>
References: <1463077910-25914-1-git-send-email-dianders@chromium.org>
Message-ID: <2865073.LogD6IIKLp@phil>

Am Donnerstag, 12. Mai 2016, 11:31:50 schrieb Douglas Anderson:

[...]

> In commit 7a03fe6f48f3 ("clk: rockchip: reset init state before mmc card
> initialization") we actually started setting this explicitly in the
> kernel, but that commit wasn't quite right and also wasn't quite
> enough.  See <https://patchwork.kernel.org/patch/9085311/> for some
> details.
> 
> Let's explicitly set this phase in dw_mmc.

[...]

> Fixes: 7a03fe6f48f3 ("clk: rockchip: reset init state before mmc card
> initialization") Signed-off-by: Douglas Anderson <dianders at chromium.org>
> Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>

I've tested this patch together with the two clock patches linked above on a 
rk3288-firefly and a rk3288-veyron-jerry. On the firefly tuning still does not 
work (probably really some regulator issue) and on veyron tuning still works 
as expected, so

Tested-by: Heiko Stuebner <heiko at sntech.de>

Doug's explanations both in the commit message and the code look sane to me, 
but I don't feel confident enough in my understanding of the matter to 
transform that into a Reviewed-by tag.


Heiko


From briannorris at chromium.org  Thu May 12 16:10:23 2016
From: briannorris at chromium.org (Brian Norris)
Date: Thu, 12 May 2016 16:10:23 -0700
Subject: [PATCH 2/2] clk: rockchip: fix the rk3399 sdmmc sample shift
In-Reply-To: <1463076197-15900-2-git-send-email-dianders@chromium.org>
References: <1463076197-15900-1-git-send-email-dianders@chromium.org>
 <1463076197-15900-2-git-send-email-dianders@chromium.org>
Message-ID: <20160512231023.GA63308@google.com>

On Thu, May 12, 2016 at 11:03:17AM -0700, Doug Anderson wrote:
> Just like every other Rockhip device, the MMC "_sample" clocks should
> have a shift of 0, not a shift of 1.  The rk3399 TRM agrees.  Presumably
> these values were set to 0 because of a typo.

I'll semi-disagree about the TRM: the TRM doesn't seem to agree with
itself, so it sometimes agrees with you and sometimes doesn't :)

On page 79 of the 2nd (?) book, it looks like {SDMMC,SDIO}_CON{0,}[2:1]
are {drv,sample}_degree. But on page 208 of the 1st book, those are put
at bits [1:0].

Perhaps we can get a straight answer from Rockchip though.

Brian

> Things _sorta_ would have worked with the incorrect sample phase shift
> because of the register layout but wouldn't have been ideal and we would
> have skipped lots of phases.  Also: we would never actually enabled the
> fine delay unless we happened to have 128 or more delay elements.
> 
> This is expected behavior before this patch:
> * Try to set:     0 degrees +   1 delay elements
>   Actually get:   0 degrees +   0 delay elements
> * Try to set:    90 degrees +   0 delay elements
>   Actually get: 180 degrees +   0 delay elements
> * Try to set:   180 degrees +   0 delay elements
>   Actually get:   0 degrees +   0 delay elements
> * Try to set:   270 degrees +   0 delay elements
>   Actually get: 180 degrees +   0 delay elements
> * Try to set:     0 degrees + 129 delay elements
>   Actually get:   0 degrees +   2 delay elements
> * Try to set:   180 degrees + 129 delay elements
>   Actually get:   0 degrees +   3 delay elements
> * Try to set:     0 degrees + 130 delay elements
>   Actually get:   0 degrees +   4 delay elements
> 
> I verified that old code had a problem by turning on debug printouts and
> seeing that the old code would report this for one SD card I had:
>   Good phase range 347-101 (115 len)
>   Good phase range 202-326 (125 len)
> 
> After my fix, it went down to one big good range for the same card.
> This is more expected:
>   Good phase range 189-1 (173 len)
>   Good phase range 82-85 (4 len)
>   Good phase range 166-168 (3 len)
> 
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> ---
>  drivers/clk/rockchip/clk-rk3399.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
> index 291543f52caa..14ff3e109e1e 100644
> --- a/drivers/clk/rockchip/clk-rk3399.c
> +++ b/drivers/clk/rockchip/clk-rk3399.c
> @@ -895,10 +895,10 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
>  			RK3399_CLKGATE_CON(6), 1, GFLAGS),
>  
>  	MMC(SCLK_SDMMC_DRV,     "sdmmc_drv",    "clk_sdmmc", RK3399_SDMMC_CON0, 1),
> -	MMC(SCLK_SDMMC_SAMPLE,  "sdmmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1),
> +	MMC(SCLK_SDMMC_SAMPLE,  "sdmmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 0),
>  
>  	MMC(SCLK_SDIO_DRV,      "sdio_drv",    "clk_sdio",  RK3399_SDIO_CON0,  1),
> -	MMC(SCLK_SDIO_SAMPLE,   "sdio_sample", "clk_sdio",  RK3399_SDIO_CON1,  1),
> +	MMC(SCLK_SDIO_SAMPLE,   "sdio_sample", "clk_sdio",  RK3399_SDIO_CON1,  0),
>  
>  	/* pcie */
>  	COMPOSITE(SCLK_PCIE_PM, "clk_pcie_pm", mux_pll_src_cpll_gpll_npll_24m_p, 0,


From heiko at sntech.de  Thu May 12 16:41:11 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 13 May 2016 01:41:11 +0200
Subject: [PATCH 1/2] Revert "clk: rockchip: reset init state before mmc
 card initialization"
In-Reply-To: <1463076197-15900-1-git-send-email-dianders@chromium.org>
References: <1463076197-15900-1-git-send-email-dianders@chromium.org>
Message-ID: <2083095.luTHhmZ9EO@phil>

Am Donnerstag, 12. Mai 2016, 11:03:16 schrieb Douglas Anderson:

Not sure what the policy is for revert-subjects in the clock-tree, but I 
guess

clk: rockchip: Revert "reset init state before mmc card initialization"

might look nicer?

> This reverts commit 7a03fe6f48f3 ("clk: rockchip: reset init state
> before mmc card initialization").

I've tested these two patches together with the dw_mmc one and everything 
that worked before still works (tuning on veyron-jerry) and everything that 
didn't work still doesn't work (tuning on firefly [likely a regulator issue]).

And re-checking the code against the TRM I now also see the mask that is to 
short (1 bit in the code vs. the actual 2 bits described in the manual)

[...]

> 1. Just this revert: likely will fix rk3288-veyron eMMC on some devices
>    + other cases; might break someone with a strange bootloader that
>    sets the phase to 0 or one that uses delay elements (pretty
>    unpredicable what would happen in that case).
> 2. Just dw_mmc patch: fixes everyone.  Effectly the dw_mmc patch will
>    totally override the broken patch and fix everything.
> 3. Both patches: fixes everyone.  Once dw_mmc is initting properly then
>    any defaults from the clock code doesn't mattery.

I'm still trying to make up my mind on how to proceed - aka in which order 
patches should get picked up.

Going with the "if it isn't upstream it doesn't exist" mantra Rob wrote 
somewhere some days ago, taking this revert should not hurt anything, as all 
the non-veyron devices currently don't support any tuning at all.

So I'd think except for the issue Shawn was originally trying to fix (for 
some non-mainline board?) it should be possible to take this patch any time 
independently of the dw_mmc part.

If Stephen or Mike want to do this directly, this is
Reviewed-by: Heiko Stuebner <heiko at sntech.de>

> Fixes: 7a03fe6f48f3 ("clk: rockchip: reset init state before mmc card
> initialization")
> Signed-off-by: Douglas Anderson <dianders at chromium.org>




From shawn.lin at rock-chips.com  Thu May 12 16:47:02 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 13 May 2016 07:47:02 +0800
Subject: [PATCH 2/2] clk: rockchip: fix the rk3399 sdmmc sample shift
In-Reply-To: <20160512231023.GA63308@google.com>
References: <1463076197-15900-1-git-send-email-dianders@chromium.org>
 <1463076197-15900-2-git-send-email-dianders@chromium.org>
 <20160512231023.GA63308@google.com>
Message-ID: <84673e7c-dd64-b2ca-5c7c-5c7f34d239d8@rock-chips.com>

? 2016/5/13 7:10, Brian Norris ??:
> On Thu, May 12, 2016 at 11:03:17AM -0700, Doug Anderson wrote:
>> Just like every other Rockhip device, the MMC "_sample" clocks should
>> have a shift of 0, not a shift of 1.  The rk3399 TRM agrees.  Presumably
>> these values were set to 0 because of a typo.
>
> I'll semi-disagree about the TRM: the TRM doesn't seem to agree with
> itself, so it sometimes agrees with you and sometimes doesn't :)
>
> On page 79 of the 2nd (?) book, it looks like {SDMMC,SDIO}_CON{0,}[2:1]
> are {drv,sample}_degree. But on page 208 of the 1st book, those are put
> at bits [1:0].
>


Please refer to Mobile Strorage Host Controller section for anything
about sdmmc/sdio. So shift should be 1.

Sometime I also get bothered to address it. Anyway, I will always keep
a eye on it from now on.....

> Perhaps we can get a straight answer from Rockchip though.
>
> Brian
>
>> Things _sorta_ would have worked with the incorrect sample phase shift
>> because of the register layout but wouldn't have been ideal and we would
>> have skipped lots of phases.  Also: we would never actually enabled the
>> fine delay unless we happened to have 128 or more delay elements.
>>
>> This is expected behavior before this patch:
>> * Try to set:     0 degrees +   1 delay elements
>>   Actually get:   0 degrees +   0 delay elements
>> * Try to set:    90 degrees +   0 delay elements
>>   Actually get: 180 degrees +   0 delay elements
>> * Try to set:   180 degrees +   0 delay elements
>>   Actually get:   0 degrees +   0 delay elements
>> * Try to set:   270 degrees +   0 delay elements
>>   Actually get: 180 degrees +   0 delay elements
>> * Try to set:     0 degrees + 129 delay elements
>>   Actually get:   0 degrees +   2 delay elements
>> * Try to set:   180 degrees + 129 delay elements
>>   Actually get:   0 degrees +   3 delay elements
>> * Try to set:     0 degrees + 130 delay elements
>>   Actually get:   0 degrees +   4 delay elements
>>
>> I verified that old code had a problem by turning on debug printouts and
>> seeing that the old code would report this for one SD card I had:
>>   Good phase range 347-101 (115 len)
>>   Good phase range 202-326 (125 len)
>>
>> After my fix, it went down to one big good range for the same card.
>> This is more expected:
>>   Good phase range 189-1 (173 len)
>>   Good phase range 82-85 (4 len)
>>   Good phase range 166-168 (3 len)
>>
>> Signed-off-by: Douglas Anderson <dianders at chromium.org>
>> ---
>>  drivers/clk/rockchip/clk-rk3399.c | 4 ++--
>>  1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
>> index 291543f52caa..14ff3e109e1e 100644
>> --- a/drivers/clk/rockchip/clk-rk3399.c
>> +++ b/drivers/clk/rockchip/clk-rk3399.c
>> @@ -895,10 +895,10 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
>>  			RK3399_CLKGATE_CON(6), 1, GFLAGS),
>>
>>  	MMC(SCLK_SDMMC_DRV,     "sdmmc_drv",    "clk_sdmmc", RK3399_SDMMC_CON0, 1),
>> -	MMC(SCLK_SDMMC_SAMPLE,  "sdmmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 1),
>> +	MMC(SCLK_SDMMC_SAMPLE,  "sdmmc_sample", "clk_sdmmc", RK3399_SDMMC_CON1, 0),
>>
>>  	MMC(SCLK_SDIO_DRV,      "sdio_drv",    "clk_sdio",  RK3399_SDIO_CON0,  1),
>> -	MMC(SCLK_SDIO_SAMPLE,   "sdio_sample", "clk_sdio",  RK3399_SDIO_CON1,  1),
>> +	MMC(SCLK_SDIO_SAMPLE,   "sdio_sample", "clk_sdio",  RK3399_SDIO_CON1,  0),
>>
>>  	/* pcie */
>>  	COMPOSITE(SCLK_PCIE_PM, "clk_pcie_pm", mux_pll_src_cpll_gpll_npll_24m_p, 0,
>
>
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Thu May 12 17:19:54 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 13 May 2016 08:19:54 +0800
Subject: [PATCH 1/2] Revert "clk: rockchip: reset init state before mmc
 card initialization"
In-Reply-To: <1463076197-15900-1-git-send-email-dianders@chromium.org>
References: <1463076197-15900-1-git-send-email-dianders@chromium.org>
Message-ID: <78aecdae-7b9b-d687-a8d3-44f476ddd73e@rock-chips.com>

On 2016/5/13 2:03, Douglas Anderson wrote:
> This reverts commit 7a03fe6f48f3 ("clk: rockchip: reset init state
> before mmc card initialization").
>
> Though not totally obvious from the commit message nor from the source
> code, that commit appears to be trying to reset the "_drv" MMC clocks to
> 90 degrees (note that the "_sample" MMC clocks have a shift of 0 so are
> not touched).

Hrrr...my fault, anyway it should be reverted in case of new register
layout in the future.

Have you found the difference of sample shift between rk3399 and former
Socs?  Per Mobile Storage Host Controller section, it migrate from
bit[1:0] to bit[2:1]...

Acutally there are three register layouts about sdmmc/sdio tuning
stuff I found. Although just two types were upstreamed, it still
caused difficulty. With your patch for dw_mmc to explictly assign
dr_phase, we keep the phase policy better to be unstood and traced.

Again sorry for commit 7a03fe6f48!

>
> The major problem here is that it doesn't properly reset things.  The
> phase is a two bit field and the commit only touches one of the two
> bits.  Thus the commit had the following affect:
> - phase   0  => phase  90
> - phase  90  => phase  90
> - phase 180  => phase 270
> - phase 270  => phase 270
>
> Things get even weirder if you happen to have a bootloader that was
> actually using delay elements (should be no reason to, but you never
> know), since those are additional bits that weren't touched by the
> original patch.
>
> This is unlikely to be what we actually want.  Checking on rk3288-veyron
> devices, I can see that the bootloader leaves these clocks as:
> - emmc:  phase 180
> - sdmmc: phase 90
> - sdio0: phase 90
>
> Thus on rk3288-veyron devices the commit we're reverting had the effect
> of changing the eMMC clock to phase 270.  This probably explains the
> scattered reports I've heard of eMMC devices not working on some veyron
> devices when using the upstream kernel.
>
> The original commit was presumably made because previously the kernel
> didn't touch the "_drv" phase at all and relied on whatever value was
> there when the kernel started.  If someone was using a bootloader that
> touched the "_drv" phase then, indeed, we should have code in the kernel
> to fix that.  ...and also, to get ideal timings, we should also have the
> kernel change the phase depending on the speed mode.  In fact, that's
> the subject of a recent patch I posted at
> <https://patchwork.kernel.org/patch/9075141/>.
>
> Ideally, we should take both the patch posted to dw_mmc and this
> revert.  Since those will likely go through different trees, here I
> describe behavior with the combos:
>
> 1. Just this revert: likely will fix rk3288-veyron eMMC on some devices
>    + other cases; might break someone with a strange bootloader that
>    sets the phase to 0 or one that uses delay elements (pretty
>    unpredicable what would happen in that case).
> 2. Just dw_mmc patch: fixes everyone.  Effectly the dw_mmc patch will
>    totally override the broken patch and fix everything.
> 3. Both patches: fixes everyone.  Once dw_mmc is initting properly then
>    any defaults from the clock code doesn't mattery.
>
> Fixes: 7a03fe6f48f3 ("clk: rockchip: reset init state before mmc card initialization")
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> ---
>  drivers/clk/rockchip/clk-mmc-phase.c | 11 -----------
>  1 file changed, 11 deletions(-)
>
> diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c
> index bc856f21f6b2..5b18265c2306 100644
> --- a/drivers/clk/rockchip/clk-mmc-phase.c
> +++ b/drivers/clk/rockchip/clk-mmc-phase.c
> @@ -41,8 +41,6 @@ static unsigned long rockchip_mmc_recalc(struct clk_hw *hw,
>  #define ROCKCHIP_MMC_DEGREE_MASK 0x3
>  #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
>  #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
> -#define ROCKCHIP_MMC_INIT_STATE_RESET 0x1
> -#define ROCKCHIP_MMC_INIT_STATE_SHIFT 1
>
>  #define PSECS_PER_SEC 1000000000000LL
>
> @@ -162,15 +160,6 @@ struct clk *rockchip_clk_register_mmc(const char *name,
>  	mmc_clock->reg = reg;
>  	mmc_clock->shift = shift;
>
> -	/*
> -	 * Assert init_state to soft reset the CLKGEN
> -	 * for mmc tuning phase and degree
> -	 */
> -	if (mmc_clock->shift == ROCKCHIP_MMC_INIT_STATE_SHIFT)
> -		writel(HIWORD_UPDATE(ROCKCHIP_MMC_INIT_STATE_RESET,
> -				     ROCKCHIP_MMC_INIT_STATE_RESET,
> -				     mmc_clock->shift), mmc_clock->reg);
> -
>  	clk = clk_register(NULL, &mmc_clock->hw);
>  	if (IS_ERR(clk))
>  		kfree(mmc_clock);
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Thu May 12 17:42:29 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 13 May 2016 08:42:29 +0800
Subject: [PATCH v2 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
In-Reply-To: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
References: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
Message-ID: <d0aaec3a-65a2-5d0f-b37b-e3f174afc0c8@rock-chips.com>

? 2016/5/13 6:35, Brian Norris ??:
> Add description for the SDHCI v5.1 eMMC controller on rk3399. Fix it to
> 200 MHz, to support all supported timing modes.
>
> Note that 'rockchip,rk3399-sdhci-5.1' is not documented; we presumably
> have a compliant Arasan controller, but let's have a rockchip property
> as the canonical backup/precautionary measure. Per Heiko's previous
> suggestion, let's not clutter the arasan doc with it.
>
> Signed-off-by: Brian Norris <briannorris at chromium.org>

Except for adding "rockchip,rk3399-sdhci-5.1", it looks nice and keeps
consistent with our local kernel-4.4 tree.

Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>

> ---
> v2:
>
>  * improved commit message
>  * assign eMMC clock to 200 MHz
>
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi | 25 ++++++++++++++++++++++++-
>  1 file changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> index 46f325a143b0..9980c2eab4e9 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -215,6 +215,19 @@
>  		status = "disabled";
>  	};
>
> +	sdhci: sdhci at fe330000 {
> +		compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
> +		reg = <0x0 0xfe330000 0x0 0x10000>;
> +		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
> +		clock-names = "clk_xin", "clk_ahb";
> +		assigned-clocks = <&cru SCLK_EMMC>;
> +		assigned-clock-rates = <200000000>;
> +		phys = <&emmc_phy>;
> +		phy-names = "phy_arasan";
> +		status = "disabled";
> +	};
> +
>  	usb_host0_ehci: usb at fe380000 {
>  		compatible = "generic-ehci";
>  		reg = <0x0 0xfe380000 0x0 0x20000>;
> @@ -481,8 +494,18 @@
>  	};
>
>  	grf: syscon at ff770000 {
> -		compatible = "rockchip,rk3399-grf", "syscon";
> +		compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
>  		reg = <0x0 0xff770000 0x0 0x10000>;
> +
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +
> +		emmc_phy: phy at f780 {
> +			compatible = "rockchip,rk3399-emmc-phy";
> +			reg = <0xf780 0x20>;
> +			#phy-cells = <0>;
> +			status = "disabled";
> +		};
>  	};
>
>  	watchdog at ff840000 {
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Thu May 12 18:02:41 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 13 May 2016 09:02:41 +0800
Subject: [PATCH 2/4] phy: rockchip-emmc: configure frequency range and
 drive impedance
In-Reply-To: <1463092986-61777-2-git-send-email-briannorris@chromium.org>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
 <1463092986-61777-2-git-send-email-briannorris@chromium.org>
Message-ID: <3695875b-09c3-cd80-3062-55d985e51f70@rock-chips.com>

Hi Brian,

On 2016/5/13 6:43, Brian Norris wrote:
> From: Shawn Lin <shawn.lin at rock-chips.com>
>
> Signal integrity analysis has suggested we set these values. Do this in
> power_on(), so that they get reconfigured after suspend/resume.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
>  drivers/phy/phy-rockchip-emmc.c | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+)
>
> diff --git a/drivers/phy/phy-rockchip-emmc.c b/drivers/phy/phy-rockchip-emmc.c
> index 48cbe691a889..5641dede32f6 100644
> --- a/drivers/phy/phy-rockchip-emmc.c
> +++ b/drivers/phy/phy-rockchip-emmc.c
> @@ -56,6 +56,19 @@
>  #define PHYCTRL_DLLRDY_SHIFT	0x5
>  #define PHYCTRL_DLLRDY_DONE	0x1
>  #define PHYCTRL_DLLRDY_GOING	0x0
> +#define PHYCTRL_FREQSEL_200M	0x0
> +#define PHYCTRL_FREQSEL_50M	0x1
> +#define PHYCTRL_FREQSEL_100M	0x2
> +#define PHYCTRL_FREQSEL_150M	0x3
> +#define PHYCTRL_FREQSEL_MASK	0x3
> +#define PHYCTRL_FREQSEL_SHIFT	0xc
> +#define PHYCTRL_DR_MASK		0x7
> +#define PHYCTRL_DR_SHIFT	0x4
> +#define PHYCTRL_DR_50OHM	0x0
> +#define PHYCTRL_DR_33OHM	0x1
> +#define PHYCTRL_DR_66OHM	0x2
> +#define PHYCTRL_DR_100OHM	0x3
> +#define PHYCTRL_DR_40OHM	0x4
>
>  struct rockchip_emmc_phy {
>  	unsigned int	reg_offset;
> @@ -154,6 +167,20 @@ static int rockchip_emmc_phy_power_on(struct phy *phy)
>  	struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
>  	int ret = 0;
>
> +	/* DLL operation: 170 to 200 MHz */

What is 170 here? Should we expose them to dt instead of hardcoding
them?

Per the commit msg, signal may vary from board to board, so I guess
50ohm may not always be the best selection?

Another thing I need to elaborate more here is that emmc phy only
supports 50/100/150/200Mhz. Presumably people love to use the highest
speed mode with its upper limiting frequency, but in case of some
special requirement or bad board design, they want to add max-frequency
in dts for emmc controller. In this case PHYCTRL_FREQSEL_XXXM should
meet the actual max-frequency, take 100M for example, otherwise
emmc_phy's  tuning block will use 200M to do some calculation but it
certainly should be 100M. This leads emmc_phy to choose the wrong
phase. Finally maybe you will see triggering re-tune easily or some
worse case of even tuning failure when probing card.


> +	regmap_write(rk_phy->reg_base,
> +		     rk_phy->reg_offset + GRF_EMMCPHY_CON0,
> +		     HIWORD_UPDATE(PHYCTRL_FREQSEL_200M,
> +				   PHYCTRL_FREQSEL_MASK,
> +				   PHYCTRL_FREQSEL_SHIFT));
> +
> +	/* Drive impedance: 50 Ohm */
> +	regmap_write(rk_phy->reg_base,
> +		     rk_phy->reg_offset + GRF_EMMCPHY_CON6,
> +		     HIWORD_UPDATE(PHYCTRL_DR_50OHM,
> +				   PHYCTRL_DR_MASK,
> +				   PHYCTRL_DR_SHIFT));
> +
>  	/* Power up emmc phy analog blocks */
>  	ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_ON);
>  	if (ret)
>


-- 
Best Regards
Shawn Lin



From dianders at chromium.org  Thu May 12 19:11:25 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 12 May 2016 19:11:25 -0700
Subject: [PATCH 1/2] Revert "clk: rockchip: reset init state before mmc
 card initialization"
In-Reply-To: <2083095.luTHhmZ9EO@phil>
References: <1463076197-15900-1-git-send-email-dianders@chromium.org>
 <2083095.luTHhmZ9EO@phil>
Message-ID: <CAD=FV=XVMQ025Z-+C4fVQUuof=9wnjvJKr2PtuJhxOVwo7TjSg@mail.gmail.com>

Heiko,

On Thu, May 12, 2016 at 4:41 PM, Heiko Stuebner <heiko at sntech.de> wrote:
> Am Donnerstag, 12. Mai 2016, 11:03:16 schrieb Douglas Anderson:
>
> Not sure what the policy is for revert-subjects in the clock-tree, but I
> guess
>
> clk: rockchip: Revert "reset init state before mmc card initialization"
>
> might look nicer?

Sure.  If you want me to re-post with that, let me know.  Else feel
free to fix when applying.


>> This reverts commit 7a03fe6f48f3 ("clk: rockchip: reset init state
>> before mmc card initialization").
>
> I've tested these two patches together with the dw_mmc one and everything
> that worked before still works (tuning on veyron-jerry) and everything that
> didn't work still doesn't work (tuning on firefly [likely a regulator issue]).
>
> And re-checking the code against the TRM I now also see the mask that is to
> short (1 bit in the code vs. the actual 2 bits described in the manual)
>
> [...]
>
>> 1. Just this revert: likely will fix rk3288-veyron eMMC on some devices
>>    + other cases; might break someone with a strange bootloader that
>>    sets the phase to 0 or one that uses delay elements (pretty
>>    unpredicable what would happen in that case).
>> 2. Just dw_mmc patch: fixes everyone.  Effectly the dw_mmc patch will
>>    totally override the broken patch and fix everything.
>> 3. Both patches: fixes everyone.  Once dw_mmc is initting properly then
>>    any defaults from the clock code doesn't mattery.
>
> I'm still trying to make up my mind on how to proceed - aka in which order
> patches should get picked up.
>
> Going with the "if it isn't upstream it doesn't exist" mantra Rob wrote
> somewhere some days ago, taking this revert should not hurt anything, as all
> the non-veyron devices currently don't support any tuning at all.

Note that this patch can still affect devices that don't use tuning.
MMC Hold times are important not just for high speed modes but even
for low speed modes.


> So I'd think except for the issue Shawn was originally trying to fix (for
> some non-mainline board?) it should be possible to take this patch any time
> independently of the dw_mmc part.

Yeah, just not sure.  Shawn: do you know which specific device you
were trying to fix with the original patch?  Is it OK to revert for
now until the dw_mmc patch lands?


From dianders at chromium.org  Thu May 12 21:36:41 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 12 May 2016 21:36:41 -0700
Subject: [PATCH 2/2] clk: rockchip: fix the rk3399 sdmmc sample shift
In-Reply-To: <84673e7c-dd64-b2ca-5c7c-5c7f34d239d8@rock-chips.com>
References: <1463076197-15900-1-git-send-email-dianders@chromium.org>
 <1463076197-15900-2-git-send-email-dianders@chromium.org>
 <20160512231023.GA63308@google.com>
 <84673e7c-dd64-b2ca-5c7c-5c7f34d239d8@rock-chips.com>
Message-ID: <CAD=FV=WEAOwhDDBHBtuzSz35i0XRZw4LbFEnFCFYd-4NVH5d-g@mail.gmail.com>

Shawn,

On Thu, May 12, 2016 at 4:47 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> ? 2016/5/13 7:10, Brian Norris ??:
>>
>> On Thu, May 12, 2016 at 11:03:17AM -0700, Doug Anderson wrote:
>>>
>>> Just like every other Rockhip device, the MMC "_sample" clocks should
>>> have a shift of 0, not a shift of 1.  The rk3399 TRM agrees.  Presumably
>>> these values were set to 0 because of a typo.
>>
>>
>> I'll semi-disagree about the TRM: the TRM doesn't seem to agree with
>> itself, so it sometimes agrees with you and sometimes doesn't :)
>>
>> On page 79 of the 2nd (?) book, it looks like {SDMMC,SDIO}_CON{0,}[2:1]
>> are {drv,sample}_degree. But on page 208 of the 1st book, those are put
>> at bits [1:0].
>>
>
>
> Please refer to Mobile Strorage Host Controller section for anything
> about sdmmc/sdio. So shift should be 1.
>
> Sometime I also get bothered to address it. Anyway, I will always keep
> a eye on it from now on.....

I still in general have mistrust for TRM docs for things like this.
Have you verified that this was an intentional change for rk3399, or
could it be a  typo?  Typically SoCs don't change this type of stuff
for no reason.

This should be possible to verify in one of two ways.  If the TRM has
a typo and things truly _do_ start at 0 instead of 1, then:

1. There will be roughly mirrors of valid ranges.
2. Things won't match up if we change tuning to use 180 course offsets
and the rest fine offsets.

It would be ideal if you could confirm with the chip guys, but if you
can't I'll try to do more tests tomorrow.


From shawn.lin at rock-chips.com  Fri May 13 00:46:54 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 13 May 2016 15:46:54 +0800
Subject: [PATCH 2/2] clk: rockchip: fix the rk3399 sdmmc sample shift
In-Reply-To: <CAD=FV=WEAOwhDDBHBtuzSz35i0XRZw4LbFEnFCFYd-4NVH5d-g@mail.gmail.com>
References: <1463076197-15900-1-git-send-email-dianders@chromium.org>
 <1463076197-15900-2-git-send-email-dianders@chromium.org>
 <20160512231023.GA63308@google.com>
 <84673e7c-dd64-b2ca-5c7c-5c7f34d239d8@rock-chips.com>
 <CAD=FV=WEAOwhDDBHBtuzSz35i0XRZw4LbFEnFCFYd-4NVH5d-g@mail.gmail.com>
Message-ID: <0261c4b4-7398-fe15-5e26-f92bfbe79f3c@rock-chips.com>

? 2016/5/13 12:36, Doug Anderson ??:
> Shawn,
>
> On Thu, May 12, 2016 at 4:47 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> ? 2016/5/13 7:10, Brian Norris ??:
>>>
>>> On Thu, May 12, 2016 at 11:03:17AM -0700, Doug Anderson wrote:
>>>>
>>>> Just like every other Rockhip device, the MMC "_sample" clocks should
>>>> have a shift of 0, not a shift of 1.  The rk3399 TRM agrees.  Presumably
>>>> these values were set to 0 because of a typo.
>>>
>>>
>>> I'll semi-disagree about the TRM: the TRM doesn't seem to agree with
>>> itself, so it sometimes agrees with you and sometimes doesn't :)
>>>
>>> On page 79 of the 2nd (?) book, it looks like {SDMMC,SDIO}_CON{0,}[2:1]
>>> are {drv,sample}_degree. But on page 208 of the 1st book, those are put
>>> at bits [1:0].
>>>
>>
>>
>> Please refer to Mobile Strorage Host Controller section for anything
>> about sdmmc/sdio. So shift should be 1.
>>
>> Sometime I also get bothered to address it. Anyway, I will always keep
>> a eye on it from now on.....
>
> I still in general have mistrust for TRM docs for things like this.
> Have you verified that this was an intentional change for rk3399, or
> could it be a  typo?  Typically SoCs don't change this type of stuff
> for no reason.
>

Typically it doesn't, but the reality is that {SDMMC,SDIO}_CON{0,}[2:1]
for drv/sample_degree both. Obviously they want to make drv stuff the
same layout as sampe stuff...

> This should be possible to verify in one of two ways.  If the TRM has
> a typo and things truly _do_ start at 0 instead of 1, then:
>
> 1. There will be roughly mirrors of valid ranges.
> 2. Things won't match up if we change tuning to use 180 course offsets
> and the rest fine offsets.
>
> It would be ideal if you could confirm with the chip guys, but if you

I have checked it before Xing upstreamed the code, but as your question 
on the TRM, I check it with the  chip guys again.

So the answer is that drv/sample stuff should refer to  Mobile Strorage
Host Controller section, and it will fit the future Socs from now on.


> can't I'll try to do more tests tomorrow.



>
>
>


-- 
Best Regards
Shawn Lin



From william.wu at rock-chips.com  Fri May 13 02:24:57 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 13 May 2016 17:24:57 +0800
Subject: [PATCH v2 1/5] usb: dwc3: of-simple: add compatible for rockchip
In-Reply-To: <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
References: <1462794377-6528-1-git-send-email-william.wu@rock-chips.com>
 <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <1463131501-22551-2-git-send-email-william.wu@rock-chips.com>

Rockchip platform merely enable usb3 clocks and
populate its children. So we can use this generic
glue layer to support Rockchip dwc3.

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v2:
- sort the list of_dwc3_simple_match (Doug)

 drivers/usb/dwc3/dwc3-of-simple.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index 9743353..6da9656 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -161,6 +161,7 @@ static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
 
 static const struct of_device_id of_dwc3_simple_match[] = {
 	{ .compatible = "qcom,dwc3" },
+	{ .compatible = "rockchip,dwc3" },
 	{ .compatible = "xlnx,zynqmp-dwc3" },
 	{ /* Sentinel */ }
 };
-- 
1.9.1




From william.wu at rock-chips.com  Fri May 13 02:24:58 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 13 May 2016 17:24:58 +0800
Subject: [PATCH v2 2/5] usb: dwc3: add dis_u2_freeclk_exists_quirk
In-Reply-To: <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
References: <1462794377-6528-1-git-send-email-william.wu@rock-chips.com>
 <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <1463131501-22551-3-git-send-email-william.wu@rock-chips.com>

Add a quirk to clear the GUSB2PHYCFG.U2_FREECLK_EXISTS bit,
which specifies whether the USB2.0 PHY provides a free-running
PHY clock, which is active when the clock control input is active.

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v2:
- None

 Documentation/devicetree/bindings/usb/dwc3.txt | 3 +++
 drivers/usb/dwc3/core.c                        | 7 +++++++
 drivers/usb/dwc3/core.h                        | 5 +++++
 drivers/usb/dwc3/platform_data.h               | 1 +
 4 files changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 7d7ce08..1ada121 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -39,6 +39,9 @@ Optional properties:
 			disabling the suspend signal to the PHY.
  - snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection
 			in PHY P3 power state.
+ - snps,dis_u2_freeclk_exists_quirk: when set, clear the u2_freeclk_exists
+			in GUSB2PHYCFG, specify that USB2 PHY doesn't provide
+			a free-running PHY clock.
  - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
 			utmi_l1_suspend_n, false when asserts utmi_sleep_n
  - snps,hird-threshold: HIRD threshold
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a590cd2..8bcd3cc 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -502,6 +502,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
 	if (dwc->dis_enblslpm_quirk)
 		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
 
+	if (dwc->dis_u2_freeclk_exists_quirk)
+		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
 	return 0;
@@ -901,6 +904,8 @@ static int dwc3_probe(struct platform_device *pdev)
 				"snps,dis_enblslpm_quirk");
 	dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
 				"snps,dis_rxdet_inp3_quirk");
+	dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
+				"snps,dis_u2_freeclk_exists_quirk");
 
 	dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
 				"snps,tx_de_emphasis_quirk");
@@ -935,6 +940,8 @@ static int dwc3_probe(struct platform_device *pdev)
 		dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
 		dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
 		dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk;
+		dwc->dis_u2_freeclk_exists_quirk =
+					pdata->dis_u2_freeclk_exists_quirk;
 
 		dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
 		if (pdata->tx_de_emphasis)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 7ddf944..ac2e6b5 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -196,6 +196,7 @@
 
 /* Global USB2 PHY Configuration Register */
 #define DWC3_GUSB2PHYCFG_PHYSOFTRST	(1 << 31)
+#define	DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS	(1 << 30)
 #define DWC3_GUSB2PHYCFG_SUSPHY		(1 << 6)
 #define DWC3_GUSB2PHYCFG_ULPI_UTMI	(1 << 4)
 #define DWC3_GUSB2PHYCFG_ENBLSLPM	(1 << 8)
@@ -770,6 +771,9 @@ struct dwc3_scratchpad_array {
  * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
  * @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
  *                      disabling the suspend signal to the PHY.
+ * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
+ *			in GUSB2PHYCFG, specify that USB2 PHY doesn't
+ *			provide a free-running PHY clock.
  * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
  * @tx_de_emphasis: Tx de-emphasis value
  * 	0	- -6dB de-emphasis
@@ -913,6 +917,7 @@ struct dwc3 {
 	unsigned		dis_u2_susphy_quirk:1;
 	unsigned		dis_enblslpm_quirk:1;
 	unsigned		dis_rxdet_inp3_quirk:1;
+	unsigned		dis_u2_freeclk_exists_quirk:1;
 
 	unsigned		tx_de_emphasis_quirk:1;
 	unsigned		tx_de_emphasis:2;
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
index 8826cca..e1a1631 100644
--- a/drivers/usb/dwc3/platform_data.h
+++ b/drivers/usb/dwc3/platform_data.h
@@ -43,6 +43,7 @@ struct dwc3_platform_data {
 	unsigned dis_u2_susphy_quirk:1;
 	unsigned dis_enblslpm_quirk:1;
 	unsigned dis_rxdet_inp3_quirk:1;
+	unsigned dis_u2_freeclk_exists_quirk:1;
 
 	unsigned tx_de_emphasis_quirk:1;
 	unsigned tx_de_emphasis:2;
-- 
1.9.1




From william.wu at rock-chips.com  Fri May 13 02:25:00 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 13 May 2016 17:25:00 +0800
Subject: [PATCH v2 4/5] usb: dwc3: add dis_del_phy_power_chg_quirk
In-Reply-To: <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
References: <1462794377-6528-1-git-send-email-william.wu@rock-chips.com>
 <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <1463131501-22551-5-git-send-email-william.wu@rock-chips.com>

Add a quirk to clear the GUSB3PIPECTL.DELAYP1TRANS bit,
which specifies whether disable delay PHY power change
from P0 to P1/P2/P3 when link state changing from U0
to U1/U2/U3 respectively.

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v2:
- None

 Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++
 drivers/usb/dwc3/core.c                        | 7 +++++++
 drivers/usb/dwc3/core.h                        | 3 +++
 drivers/usb/dwc3/platform_data.h               | 1 +
 4 files changed, 13 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 34d13a5..bd5bef0 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -42,6 +42,8 @@ Optional properties:
  - snps,dis_u2_freeclk_exists_quirk: when set, clear the u2_freeclk_exists
 			in GUSB2PHYCFG, specify that USB2 PHY doesn't provide
 			a free-running PHY clock.
+ - snps,dis_del_phy_power_chg_quirk: when set core will change PHY power
+			from P0 to P1/P2/P3 without delay.
  - snps,phyif_utmi_quirk: when set core will set phyif UTMI+ interface.
  - snps,phyif_utmi: the value to configure the core to support a UTMI+ PHY
 			with an 8- or 16-bit interface. Value 0 select 8-bit
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index d99c170..c06870c 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -451,6 +451,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
 	if (dwc->dis_u3_susphy_quirk)
 		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
 
+	if (dwc->dis_del_phy_power_chg_quirk)
+		reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
 
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
@@ -920,6 +923,8 @@ static int dwc3_probe(struct platform_device *pdev)
 				"snps,dis_rxdet_inp3_quirk");
 	dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
 				"snps,dis_u2_freeclk_exists_quirk");
+	dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
+				"snps,dis_del_phy_power_chg_quirk");
 
 	dwc->phyif_utmi_quirk = device_property_read_bool(dev,
 				"snps,phyif_utmi_quirk");
@@ -960,6 +965,8 @@ static int dwc3_probe(struct platform_device *pdev)
 		dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk;
 		dwc->dis_u2_freeclk_exists_quirk =
 					pdata->dis_u2_freeclk_exists_quirk;
+		dwc->dis_del_phy_power_chg_quirk =
+					pdata->dis_del_phy_power_chg_quirk;
 
 		dwc->phyif_utmi_quirk = pdata->phyif_utmi_quirk;
 		if (pdata->phyif_utmi)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index e1fcae8..abed84f 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -780,6 +780,8 @@ struct dwc3_scratchpad_array {
  * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
  *			in GUSB2PHYCFG, specify that USB2 PHY doesn't
  *			provide a free-running PHY clock.
+ * @dis_del_phy_power_chg_quirk: set if we disable delay phy power
+ *			change quirk.
  * @phyif_utmi_quirk: set if we enable phyif UTMI+ quirk
  * @phyif_utmi: UTMI+ PHY interface value
  *	0	- 8 bits
@@ -928,6 +930,7 @@ struct dwc3 {
 	unsigned		dis_enblslpm_quirk:1;
 	unsigned		dis_rxdet_inp3_quirk:1;
 	unsigned		dis_u2_freeclk_exists_quirk:1;
+	unsigned		dis_del_phy_power_chg_quirk:1;
 
 	unsigned		phyif_utmi_quirk:1;
 	unsigned		phyif_utmi:1;
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
index b521565..ab45d91 100644
--- a/drivers/usb/dwc3/platform_data.h
+++ b/drivers/usb/dwc3/platform_data.h
@@ -44,6 +44,7 @@ struct dwc3_platform_data {
 	unsigned dis_enblslpm_quirk:1;
 	unsigned dis_rxdet_inp3_quirk:1;
 	unsigned dis_u2_freeclk_exists_quirk:1;
+	unsigned dis_del_phy_power_chg_quirk:1;
 
 	unsigned phyif_utmi_quirk:1;
 	unsigned phyif_utmi:1;
-- 
1.9.1




From william.wu at rock-chips.com  Fri May 13 02:24:59 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 13 May 2016 17:24:59 +0800
Subject: [PATCH v2 3/5] usb: dwc3: add phyif_utmi_quirk
In-Reply-To: <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
References: <1462794377-6528-1-git-send-email-william.wu@rock-chips.com>
 <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <1463131501-22551-4-git-send-email-william.wu@rock-chips.com>

Add a quirk to configure the core to support the
UTMI+ PHY with an 8- or 16-bit interface. UTMI+ PHY
interface is hardware property, and it's platform
dependent. Normall, the PHYIf can be configured
during coreconsultant. But for some specific usb
cores(e.g. rk3399 soc dwc3), the default PHYIf
configuration value is fault, so we need to
reconfigure it by software.

And refer to the dwc3 databook, the GUSB2PHYCFG.USBTRDTIM
must be set to the corresponding value according to
the UTMI+ PHY interface.

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v2:
- add a quirk for phyif_utmi (Felipe)

 Documentation/devicetree/bindings/usb/dwc3.txt |  4 ++++
 drivers/usb/dwc3/core.c                        | 23 +++++++++++++++++++++++
 drivers/usb/dwc3/core.h                        | 12 ++++++++++++
 drivers/usb/dwc3/platform_data.h               |  2 ++
 4 files changed, 41 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 1ada121..34d13a5 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -42,6 +42,10 @@ Optional properties:
  - snps,dis_u2_freeclk_exists_quirk: when set, clear the u2_freeclk_exists
 			in GUSB2PHYCFG, specify that USB2 PHY doesn't provide
 			a free-running PHY clock.
+ - snps,phyif_utmi_quirk: when set core will set phyif UTMI+ interface.
+ - snps,phyif_utmi: the value to configure the core to support a UTMI+ PHY
+			with an 8- or 16-bit interface. Value 0 select 8-bit
+			interface, value 1 select 16-bit interface.
  - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
 			utmi_l1_suspend_n, false when asserts utmi_sleep_n
  - snps,hird-threshold: HIRD threshold
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 8bcd3cc..d99c170 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -410,6 +410,7 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
 static int dwc3_phy_setup(struct dwc3 *dwc)
 {
 	u32 reg;
+	u32 usbtrdtim;
 	int ret;
 
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
@@ -505,6 +506,15 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
 	if (dwc->dis_u2_freeclk_exists_quirk)
 		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
 
+	if (dwc->phyif_utmi_quirk) {
+		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+		       DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+		usbtrdtim = dwc->phyif_utmi ? USBTRDTIM_UTMI_16_BIT :
+			    USBTRDTIM_UTMI_8_BIT;
+		reg |= DWC3_GUSB2PHYCFG_PHYIF(dwc->phyif_utmi) |
+		       DWC3_GUSB2PHYCFG_USBTRDTIM(usbtrdtim);
+	}
+
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
 	return 0;
@@ -800,6 +810,7 @@ static int dwc3_probe(struct platform_device *pdev)
 	struct resource		*res;
 	struct dwc3		*dwc;
 	u8			lpm_nyet_threshold;
+	u8			phyif_utmi;
 	u8			tx_de_emphasis;
 	u8			hird_threshold;
 	u32			fladj = 0;
@@ -857,6 +868,9 @@ static int dwc3_probe(struct platform_device *pdev)
 	/* default to highest possible threshold */
 	lpm_nyet_threshold = 0xff;
 
+	/* default to UTMI+ 8-bit interface */
+	phyif_utmi = 0;
+
 	/* default to -3.5dB de-emphasis */
 	tx_de_emphasis = 1;
 
@@ -907,6 +921,10 @@ static int dwc3_probe(struct platform_device *pdev)
 	dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
 				"snps,dis_u2_freeclk_exists_quirk");
 
+	dwc->phyif_utmi_quirk = device_property_read_bool(dev,
+				"snps,phyif_utmi_quirk");
+	device_property_read_u8(dev, "snps,phyif_utmi",
+				&phyif_utmi);
 	dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
 				"snps,tx_de_emphasis_quirk");
 	device_property_read_u8(dev, "snps,tx_de_emphasis",
@@ -943,6 +961,10 @@ static int dwc3_probe(struct platform_device *pdev)
 		dwc->dis_u2_freeclk_exists_quirk =
 					pdata->dis_u2_freeclk_exists_quirk;
 
+		dwc->phyif_utmi_quirk = pdata->phyif_utmi_quirk;
+		if (pdata->phyif_utmi)
+			phyif_utmi = pdata->phyif_utmi;
+
 		dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
 		if (pdata->tx_de_emphasis)
 			tx_de_emphasis = pdata->tx_de_emphasis;
@@ -952,6 +974,7 @@ static int dwc3_probe(struct platform_device *pdev)
 	}
 
 	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+	dwc->phyif_utmi = phyif_utmi;
 	dwc->tx_de_emphasis = tx_de_emphasis;
 
 	dwc->hird_threshold = hird_threshold
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index ac2e6b5..e1fcae8 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -200,6 +200,12 @@
 #define DWC3_GUSB2PHYCFG_SUSPHY		(1 << 6)
 #define DWC3_GUSB2PHYCFG_ULPI_UTMI	(1 << 4)
 #define DWC3_GUSB2PHYCFG_ENBLSLPM	(1 << 8)
+#define DWC3_GUSB2PHYCFG_PHYIF(n)	(n << 3)
+#define DWC3_GUSB2PHYCFG_PHYIF_MASK	DWC3_GUSB2PHYCFG_PHYIF(1)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM(n)	(n << 10)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM_MASK	DWC3_GUSB2PHYCFG_USBTRDTIM(0xf)
+#define USBTRDTIM_UTMI_8_BIT		9
+#define USBTRDTIM_UTMI_16_BIT		5
 
 /* Global USB2 PHY Vendor Control Register */
 #define DWC3_GUSB2PHYACC_NEWREGREQ	(1 << 25)
@@ -774,6 +780,10 @@ struct dwc3_scratchpad_array {
  * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
  *			in GUSB2PHYCFG, specify that USB2 PHY doesn't
  *			provide a free-running PHY clock.
+ * @phyif_utmi_quirk: set if we enable phyif UTMI+ quirk
+ * @phyif_utmi: UTMI+ PHY interface value
+ *	0	- 8 bits
+ *	1	- 16 bits
  * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
  * @tx_de_emphasis: Tx de-emphasis value
  * 	0	- -6dB de-emphasis
@@ -919,6 +929,8 @@ struct dwc3 {
 	unsigned		dis_rxdet_inp3_quirk:1;
 	unsigned		dis_u2_freeclk_exists_quirk:1;
 
+	unsigned		phyif_utmi_quirk:1;
+	unsigned		phyif_utmi:1;
 	unsigned		tx_de_emphasis_quirk:1;
 	unsigned		tx_de_emphasis:2;
 };
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
index e1a1631..b521565 100644
--- a/drivers/usb/dwc3/platform_data.h
+++ b/drivers/usb/dwc3/platform_data.h
@@ -45,6 +45,8 @@ struct dwc3_platform_data {
 	unsigned dis_rxdet_inp3_quirk:1;
 	unsigned dis_u2_freeclk_exists_quirk:1;
 
+	unsigned phyif_utmi_quirk:1;
+	unsigned phyif_utmi:1;
 	unsigned tx_de_emphasis_quirk:1;
 	unsigned tx_de_emphasis:2;
 
-- 
1.9.1




From william.wu at rock-chips.com  Fri May 13 02:24:56 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 13 May 2016 17:24:56 +0800
Subject: [PATCH v2 0/5] support rockchip dwc3 driver
In-Reply-To: <1462794377-6528-1-git-send-email-william.wu@rock-chips.com>
References: <1462794377-6528-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>

This series add support for rockchip dwc3 driver,
and add additional optional properties for specific
platforms (e.g., rockchip platform).

William Wu (5):
  usb: dwc3: of-simple: add compatible for rockchip
  usb: dwc3: add dis_u2_freeclk_exists_quirk
  usb: dwc3: add phyif_utmi_quirk
  usb: dwc3: add dis_del_phy_power_chg_quirk
  usb: dwc3: rockchip: add devicetree bindings documentation

 Documentation/devicetree/bindings/usb/dwc3.txt     |  9 +++++
 .../devicetree/bindings/usb/rockchip,dwc3.txt      | 45 ++++++++++++++++++++++
 drivers/usb/dwc3/core.c                            | 39 ++++++++++++++++++-
 drivers/usb/dwc3/core.h                            | 20 ++++++++++
 drivers/usb/dwc3/dwc3-of-simple.c                  |  1 +
 drivers/usb/dwc3/platform_data.h                   |  4 ++
 6 files changed, 117 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt

-- 
1.9.1




From heiko at sntech.de  Fri May 13 02:30:40 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 13 May 2016 11:30:40 +0200
Subject: [PATCH v2 0/5] support rockchip dwc3 driver
In-Reply-To: <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
References: <1462794377-6528-1-git-send-email-william.wu@rock-chips.com>
 <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <2826455.lpNbMfItd8@phil>

Hi William,

Am Freitag, 13. Mai 2016, 17:24:56 schrieb William Wu:
> This series add support for rockchip dwc3 driver,
> and add additional optional properties for specific
> platforms (e.g., rockchip platform).

when submitting new versions of patchsets please also start a new thread.
It is hard to find such new versions in a big threaded mail view later on.

No need to resend this v2, just to keep in mind for later patches.


Heiko


From balbi at kernel.org  Fri May 13 02:37:11 2016
From: balbi at kernel.org (Felipe Balbi)
Date: Fri, 13 May 2016 12:37:11 +0300
Subject: [PATCH v2 0/5] support rockchip dwc3 driver
In-Reply-To: <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
References: <1462794377-6528-1-git-send-email-william.wu@rock-chips.com>
 <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <87wpmyqoxk.fsf@linux.intel.com>


Hi,

William Wu <william.wu at rock-chips.com> writes:
> This series add support for rockchip dwc3 driver,
> and add additional optional properties for specific
> platforms (e.g., rockchip platform).
>
> William Wu (5):
>   usb: dwc3: of-simple: add compatible for rockchip
>   usb: dwc3: add dis_u2_freeclk_exists_quirk
>   usb: dwc3: add phyif_utmi_quirk
>   usb: dwc3: add dis_del_phy_power_chg_quirk
>   usb: dwc3: rockchip: add devicetree bindings documentation
>
>  Documentation/devicetree/bindings/usb/dwc3.txt     |  9 +++++
>  .../devicetree/bindings/usb/rockchip,dwc3.txt      | 45 ++++++++++++++++++++++
>  drivers/usb/dwc3/core.c                            | 39 ++++++++++++++++++-
>  drivers/usb/dwc3/core.h                            | 20 ++++++++++
>  drivers/usb/dwc3/dwc3-of-simple.c                  |  1 +
>  drivers/usb/dwc3/platform_data.h                   |  4 ++
>  6 files changed, 117 insertions(+), 1 deletion(-)
>  create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt

I didn't get patch 5/5 :-s

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 818 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160513/b3b15bda/attachment.sig>

From william.wu at rock-chips.com  Fri May 13 02:48:21 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 13 May 2016 17:48:21 +0800
Subject: [PATCH v2 0/5] support rockchip dwc3 driver
In-Reply-To: <87wpmyqoxk.fsf@linux.intel.com>
References: <1462794377-6528-1-git-send-email-william.wu@rock-chips.com>
 <1463131501-22551-1-git-send-email-william.wu@rock-chips.com>
 <87wpmyqoxk.fsf@linux.intel.com>
Message-ID: <5735A2E5.2020505@rock-chips.com>

Dear Felipe,
On 05/13/2016 05:37 PM, Felipe Balbi wrote:
> Hi,
>
> William Wu <william.wu at rock-chips.com> writes:
>> This series add support for rockchip dwc3 driver,
>> and add additional optional properties for specific
>> platforms (e.g., rockchip platform).
>>
>> William Wu (5):
>>    usb: dwc3: of-simple: add compatible for rockchip
>>    usb: dwc3: add dis_u2_freeclk_exists_quirk
>>    usb: dwc3: add phyif_utmi_quirk
>>    usb: dwc3: add dis_del_phy_power_chg_quirk
>>    usb: dwc3: rockchip: add devicetree bindings documentation
>>
>>   Documentation/devicetree/bindings/usb/dwc3.txt     |  9 +++++
>>   .../devicetree/bindings/usb/rockchip,dwc3.txt      | 45 ++++++++++++++++++++++
>>   drivers/usb/dwc3/core.c                            | 39 ++++++++++++++++++-
>>   drivers/usb/dwc3/core.h                            | 20 ++++++++++
>>   drivers/usb/dwc3/dwc3-of-simple.c                  |  1 +
>>   drivers/usb/dwc3/platform_data.h                   |  4 ++
>>   6 files changed, 117 insertions(+), 1 deletion(-)
>>   create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
> I didn't get patch 5/5 :-s
Sorry, maybe there are something wrong with our mailbox server.
I'll resend patch 5/5 later.
>




From william.wu at rock-chips.com  Fri May 13 02:52:35 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 13 May 2016 17:52:35 +0800
Subject: [PATCH v2 5/5] usb: dwc3: rockchip: add devicetree bindings
 documentation
Message-ID: <1463133155-20047-1-git-send-email-william.wu@rock-chips.com>

This patch documents the device tree documentation required for
Rockchip USB3.0 core wrapper consist of USB3.0 IP from Synopsys.

It could operate in device mode (SS, HS, FS) and host
mode (SS, HS, FS, LS).

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v2:
- add rockchip,dwc3.txt to Documentation/devicetree/bindings/ (Felipe, Brian)

 .../devicetree/bindings/usb/rockchip,dwc3.txt      | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt

diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
new file mode 100644
index 0000000..10303d9
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
@@ -0,0 +1,45 @@
+Rockchip SuperSpeed DWC3 USB SoC controller
+
+Required properties:
+- compatible:	should contain "rockchip,dwc3"
+- clocks:		A list of phandle + clock-specifier pairs for the
+				clocks listed in clock-names
+- clock-names:	Should contain the following:
+  "clk_usb3otg0_ref"	Controller reference clk
+  "clk_usb3otg0_suspend"Controller suspend clk, can use 24 MHz or 32 KHz
+  "aclk_usb3"		Master/Core clock, have to be >= 62.5 MHz for SS operation
+
+
+Optional clocks:
+  "aclk_usb3otg0"	Aclk for specific usb controller clock.
+  "aclk_usb3_rksoc_axi_perf"  USB AXI perf clock.  Not present on all platforms.
+  "aclk_usb3_grf"	USB grf clock.  Not present on all platforms.
+
+Required child node:
+A child node must exist to represent the core DWC3 IP block. The name of
+the node is not important. The content of the node is defined in dwc3.txt.
+
+Phy documentation is provided in the following places:
+
+Example device nodes:
+
+	usbdrd3_0: usb at fe800000 {
+		compatible = "rockchip,dwc3";
+		clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
+			 <&cru ACLK_USB3>, <&cru ACLK_USB3OTG0>,
+			 <&cru ACLK_USB3_RKSOC_AXI_PERF>, <&cru ACLK_USB3_GRF>;
+		clock-names = "clk_usb3otg0_ref", "clk_usb3otg0_suspend",
+			      "aclk_usb3", "aclk_usb3otg0",
+			      "aclk_usb3_rksoc_axi_perf", "aclk_usb3_grf";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "disabled";
+		usbdrd_dwc3_0: dwc3 {
+			compatible = "snps,dwc3";
+			reg = <0x0 0xfe800000 0x0 0x100000>;
+			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+			dr_mode = "otg";
+			status = "disabled";
+		};
+	};
-- 
1.9.1




From william.wu at rock-chips.com  Fri May 13 03:05:26 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 13 May 2016 18:05:26 +0800
Subject: [PATCH] usb: dwc3: add DWC3_GUCTL1 reg for debug
Message-ID: <1463133926-7366-1-git-send-email-william.wu@rock-chips.com>

GUCTL1 reg has some useful functions which can be
written by user. For rockchip platform, we set
GUCTL1.DEV_FORCE_20_CLK_FOR_30_CLK (bit26, applicable
for the core is programmed to operate in 2.0 device
only) to 1 in bootrom, and after start the kernel,
we want to check whether this bit can be reset to
default 0 after the core reset. Dump GUCTL1 reg from
debugfs is more convenient for us.

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v2:
- add commit log

 drivers/usb/dwc3/core.h    | 1 +
 drivers/usb/dwc3/debugfs.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index abed84f..c4758d5 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -86,6 +86,7 @@
 #define DWC3_GCTL		0xc110
 #define DWC3_GEVTEN		0xc114
 #define DWC3_GSTS		0xc118
+#define DWC3_GUCTL1		0xc11c
 #define DWC3_GSNPSID		0xc120
 #define DWC3_GGPIO		0xc124
 #define DWC3_GUID		0xc128
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index b1dd3c6..f3c9f44 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -47,6 +47,7 @@ static const struct debugfs_reg32 dwc3_regs[] = {
 	dump_register(GCTL),
 	dump_register(GEVTEN),
 	dump_register(GSTS),
+	dump_register(GUCTL1),
 	dump_register(GSNPSID),
 	dump_register(GGPIO),
 	dump_register(GUID),
-- 
1.9.1




From william.wu at rock-chips.com  Fri May 13 03:07:50 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 13 May 2016 18:07:50 +0800
Subject: [PATCH] usb: dwc3: add DWC3_GUCTL1 reg for debug
In-Reply-To: <1463133926-7366-1-git-send-email-william.wu@rock-chips.com>
References: <1463133926-7366-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <5735A776.9050602@rock-chips.com>

On 05/13/2016 06:05 PM, William Wu wrote:
> GUCTL1 reg has some useful functions which can be
> written by user. For rockchip platform, we set
> GUCTL1.DEV_FORCE_20_CLK_FOR_30_CLK (bit26, applicable
> for the core is programmed to operate in 2.0 device
> only) to 1 in bootrom, and after start the kernel,
> we want to check whether this bit can be reset to
> default 0 after the core reset. Dump GUCTL1 reg from
> debugfs is more convenient for us.
>
> Signed-off-by: William Wu <william.wu at rock-chips.com>
> ---
> Changes in v2:
> - add commit log
>
>   drivers/usb/dwc3/core.h    | 1 +
>   drivers/usb/dwc3/debugfs.c | 1 +
>   2 files changed, 2 insertions(+)
>
> diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
> index abed84f..c4758d5 100644
> --- a/drivers/usb/dwc3/core.h
> +++ b/drivers/usb/dwc3/core.h
> @@ -86,6 +86,7 @@
>   #define DWC3_GCTL		0xc110
>   #define DWC3_GEVTEN		0xc114
>   #define DWC3_GSTS		0xc118
> +#define DWC3_GUCTL1		0xc11c
>   #define DWC3_GSNPSID		0xc120
>   #define DWC3_GGPIO		0xc124
>   #define DWC3_GUID		0xc128
> diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
> index b1dd3c6..f3c9f44 100644
> --- a/drivers/usb/dwc3/debugfs.c
> +++ b/drivers/usb/dwc3/debugfs.c
> @@ -47,6 +47,7 @@ static const struct debugfs_reg32 dwc3_regs[] = {
>   	dump_register(GCTL),
>   	dump_register(GEVTEN),
>   	dump_register(GSTS),
> +	dump_register(GUCTL1),
>   	dump_register(GSNPSID),
>   	dump_register(GGPIO),
>   	dump_register(GUID),
I'm sorry for forgot to add v2 in commit. I'll resend it later.



From william.wu at rock-chips.com  Fri May 13 03:13:46 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 13 May 2016 18:13:46 +0800
Subject: [PATCH v2] usb: dwc3: add DWC3_GUCTL1 reg for debug
Message-ID: <1463134426-16599-1-git-send-email-william.wu@rock-chips.com>

GUCTL1 reg has some useful functions which can be
written by user. For rockchip platform, we set
GUCTL1.DEV_FORCE_20_CLK_FOR_30_CLK (bit26, applicable
for the core is programmed to operate in 2.0 device
only) to 1 in bootrom, and after start the kernel,
we want to check whether this bit can be reset to
default 0 after the core reset. Dump GUCTL1 reg from
debugfs is more convenient for us.

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v2:
- add commit log

 drivers/usb/dwc3/core.h    | 1 +
 drivers/usb/dwc3/debugfs.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index abed84f..c4758d5 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -86,6 +86,7 @@
 #define DWC3_GCTL		0xc110
 #define DWC3_GEVTEN		0xc114
 #define DWC3_GSTS		0xc118
+#define DWC3_GUCTL1		0xc11c
 #define DWC3_GSNPSID		0xc120
 #define DWC3_GGPIO		0xc124
 #define DWC3_GUID		0xc128
diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c
index b1dd3c6..f3c9f44 100644
--- a/drivers/usb/dwc3/debugfs.c
+++ b/drivers/usb/dwc3/debugfs.c
@@ -47,6 +47,7 @@ static const struct debugfs_reg32 dwc3_regs[] = {
 	dump_register(GCTL),
 	dump_register(GEVTEN),
 	dump_register(GSTS),
+	dump_register(GUCTL1),
 	dump_register(GSNPSID),
 	dump_register(GGPIO),
 	dump_register(GUID),
-- 
1.9.1




From william.wu at rock-chips.com  Fri May 13 03:30:42 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 13 May 2016 18:30:42 +0800
Subject: [PATCH] usb: gadget: composite: don't queue OS desc req if length is
 invalid
Message-ID: <1463135442-15970-1-git-send-email-william.wu@rock-chips.com>

In OS descriptors handling, if ctrl->bRequestType is
USB_RECIP_DEVICE and w_index != 0x4 or (w_value >> 8)
is true, it will not assign a valid value to req->length,
but use the default value(-EOPNOTSUPP), and queue an
OS desc request with the invalid req->length. It always
happens on the platforms which use os_desc (for example:
rk3366, rk3399), and cause kernel panic as follows
(use dwc3 driver):

Unable to handle kernel paging request at virtual address ffffffc0f7e00000
Internal error: Oops: 96000146 [#1] PREEMPT SMP
PC is at __dma_clean_range+0x18/0x30
LR is at __swiotlb_map_page+0x50/0x64
Call trace:
[<ffffffc0000930f8>] __dma_clean_range+0x18/0x30
[<ffffffc00062214c>] usb_gadget_map_request+0x134/0x1b0
[<ffffffc0005c289c>] __dwc3_ep0_do_control_data+0x110/0x14c
[<ffffffc0005c2d38>] __dwc3_gadget_ep0_queue+0x198/0x1b8
[<ffffffc0005c2e18>] dwc3_gadget_ep0_queue+0xc0/0xe8
[<ffffffc00061cfec>] composite_ep0_queue.constprop.14+0x34/0x98
[<ffffffc00061dfb0>] composite_setup+0xf60/0x100c
[<ffffffc0006204dc>] android_setup+0xd8/0x138
[<ffffffc0005c29a4>] dwc3_ep0_delegate_req+0x34/0x50
[<ffffffc0005c3534>] dwc3_ep0_interrupt+0x5dc/0xb58
[<ffffffc0005c0c3c>] dwc3_thread_interrupt+0x15c/0xa24

With this patch, the gadget driver will not queue
a request and return immediately if req->length is
invalid. And the usb controller driver can handle
the unsupport request correctly.

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
 drivers/usb/gadget/composite.c | 21 +++++++++++++--------
 1 file changed, 13 insertions(+), 8 deletions(-)

diff --git a/drivers/usb/gadget/composite.c b/drivers/usb/gadget/composite.c
index d67de0d..eb64848 100644
--- a/drivers/usb/gadget/composite.c
+++ b/drivers/usb/gadget/composite.c
@@ -1868,14 +1868,19 @@ unknown:
 				}
 				break;
 			}
-			req->length = value;
-			req->context = cdev;
-			req->zero = value < w_length;
-			value = composite_ep0_queue(cdev, req, GFP_ATOMIC);
-			if (value < 0) {
-				DBG(cdev, "ep_queue --> %d\n", value);
-				req->status = 0;
-				composite_setup_complete(gadget->ep0, req);
+
+			if (value >= 0) {
+				req->length = value;
+				req->context = cdev;
+				req->zero = value < w_length;
+				value = composite_ep0_queue(cdev, req,
+							    GFP_ATOMIC);
+				if (value < 0) {
+					DBG(cdev, "ep_queue --> %d\n", value);
+					req->status = 0;
+					composite_setup_complete(gadget->ep0,
+								 req);
+				}
 			}
 			return value;
 		}
-- 
1.9.1




From broonie at kernel.org  Fri May 13 04:20:56 2016
From: broonie at kernel.org (Mark Brown)
Date: Fri, 13 May 2016 12:20:56 +0100
Subject: [PATCH v5 3/6] regulator: rk808: Add regulator driver for RK818
In-Reply-To: <1462886340-7893-4-git-send-email-w.egorov@phytec.de>
References: <1462886340-7893-1-git-send-email-w.egorov@phytec.de>
 <1462886340-7893-4-git-send-email-w.egorov@phytec.de>
Message-ID: <20160513112055.GE22038@sirena.org.uk>

On Tue, May 10, 2016 at 03:18:57PM +0200, Wadim Egorov wrote:
> Add support for the rk818 regulator. The regulator module consists
> of 4 DCDCs, 9 LDOs, 1 switch and 1 BOOST converter which is used to
> power OTG and HDMI5V.

Acked-by: Mark Brown <broonie at kernel.org>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160513/8d1d2b48/attachment.sig>

From dianders at chromium.org  Fri May 13 09:38:16 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 09:38:16 -0700
Subject: [PATCH 2/2] clk: rockchip: fix the rk3399 sdmmc sample shift
In-Reply-To: <0261c4b4-7398-fe15-5e26-f92bfbe79f3c@rock-chips.com>
References: <1463076197-15900-1-git-send-email-dianders@chromium.org>
 <1463076197-15900-2-git-send-email-dianders@chromium.org>
 <20160512231023.GA63308@google.com>
 <84673e7c-dd64-b2ca-5c7c-5c7f34d239d8@rock-chips.com>
 <CAD=FV=WEAOwhDDBHBtuzSz35i0XRZw4LbFEnFCFYd-4NVH5d-g@mail.gmail.com>
 <0261c4b4-7398-fe15-5e26-f92bfbe79f3c@rock-chips.com>
Message-ID: <CAD=FV=UNVHrGeKj0N_1WQvL+PNBTrPTj1xmk-63F4hJhPuvkug@mail.gmail.com>

Shawn,

On Fri, May 13, 2016 at 12:46 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> This should be possible to verify in one of two ways.  If the TRM has
>> a typo and things truly _do_ start at 0 instead of 1, then:
>>
>> 1. There will be roughly mirrors of valid ranges.
>> 2. Things won't match up if we change tuning to use 180 course offsets
>> and the rest fine offsets.
>>
>> It would be ideal if you could confirm with the chip guys, but if you
>
>
> I have checked it before Xing upstreamed the code, but as your question on
> the TRM, I check it with the  chip guys again.
>
> So the answer is that drv/sample stuff should refer to  Mobile Strorage
> Host Controller section, and it will fit the future Socs from now on.

OK, awesome.  I also did more quick tests by forcing dw_mmc to give me
extra details about the tuning.  These tests agree with you.

Please consider this patch abandoned.  Note that the previous patch
(1/2) is still good as far as I know, so just this patch (2/2) should
be abandoned.

Thanks!  :)

-Doug


From briannorris at chromium.org  Fri May 13 11:42:16 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 11:42:16 -0700
Subject: [PATCH 1/2] clk: rockchip: mark rk3399 GIC clocks as critical
Message-ID: <1463164937-91089-1-git-send-email-briannorris@chromium.org>

We never want to kill the GIC.

Noticed when making other clock fixups, and seeing the newly-constructed
clock tree try to disable cpll, where we had this parent structure:

  aclk_gic <------\
                  |--- aclk_gic_pre <-- cpll <-- pll_cpll
  aclk_gic_noc <--/

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 drivers/clk/rockchip/clk-rk3399.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
index 291543f52caa..145756c4f3c8 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -1466,6 +1466,8 @@ static struct rockchip_clk_branch rk3399_clk_pmu_branches[] __initdata = {
 
 static const char *const rk3399_cru_critical_clocks[] __initconst = {
 	"aclk_cci_pre",
+	"aclk_gic",
+	"aclk_gic_noc",
 	"pclk_perilp0",
 	"pclk_perilp0",
 	"hclk_perilp0",
-- 
2.8.0.rc3.226.g39d4020



From briannorris at chromium.org  Fri May 13 11:42:17 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 11:42:17 -0700
Subject: [PATCH 2/2] clk: rockchip: fix incorrect parent for rk3399's {c,
 g}pll_aclk_perihp_src
In-Reply-To: <1463164937-91089-1-git-send-email-briannorris@chromium.org>
References: <1463164937-91089-1-git-send-email-briannorris@chromium.org>
Message-ID: <1463164937-91089-2-git-send-email-briannorris@chromium.org>

From: Xing Zheng <zhengxing at rock-chips.com>

There was a typo, swapping 'c' <--> 'g'.

Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 drivers/clk/rockchip/clk-rk3399.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
index 145756c4f3c8..9f86bfef70f7 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -832,9 +832,9 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
 			RK3399_CLKGATE_CON(13), 1, GFLAGS),
 
 	/* perihp */
-	GATE(0, "cpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED,
+	GATE(0, "cpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED,
 			RK3399_CLKGATE_CON(5), 0, GFLAGS),
-	GATE(0, "gpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED,
+	GATE(0, "gpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED,
 			RK3399_CLKGATE_CON(5), 1, GFLAGS),
 	COMPOSITE(ACLK_PERIHP, "aclk_perihp", mux_aclk_perihp_p, CLK_IGNORE_UNUSED,
 			RK3399_CLKSEL_CON(14), 7, 1, MFLAGS, 0, 5, DFLAGS,
-- 
2.8.0.rc3.226.g39d4020



From dianders at chromium.org  Fri May 13 11:46:33 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 11:46:33 -0700
Subject: [PATCH 2/4] phy: rockchip-emmc: configure frequency range and
 drive impedance
In-Reply-To: <3695875b-09c3-cd80-3062-55d985e51f70@rock-chips.com>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
 <1463092986-61777-2-git-send-email-briannorris@chromium.org>
 <3695875b-09c3-cd80-3062-55d985e51f70@rock-chips.com>
Message-ID: <CAD=FV=UwocUy_bOUrJZB47taHWdV1KGkvi5CyZf74Y8cvGgVmw@mail.gmail.com>

Shawn,

On Thu, May 12, 2016 at 6:02 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> Hi Brian,
>
>
> On 2016/5/13 6:43, Brian Norris wrote:
>>
>> From: Shawn Lin <shawn.lin at rock-chips.com>
>>
>> Signal integrity analysis has suggested we set these values. Do this in
>> power_on(), so that they get reconfigured after suspend/resume.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> Signed-off-by: Brian Norris <briannorris at chromium.org>
>> ---
>>  drivers/phy/phy-rockchip-emmc.c | 27 +++++++++++++++++++++++++++
>>  1 file changed, 27 insertions(+)
>>
>> diff --git a/drivers/phy/phy-rockchip-emmc.c
>> b/drivers/phy/phy-rockchip-emmc.c
>> index 48cbe691a889..5641dede32f6 100644
>> --- a/drivers/phy/phy-rockchip-emmc.c
>> +++ b/drivers/phy/phy-rockchip-emmc.c
>> @@ -56,6 +56,19 @@
>>  #define PHYCTRL_DLLRDY_SHIFT   0x5
>>  #define PHYCTRL_DLLRDY_DONE    0x1
>>  #define PHYCTRL_DLLRDY_GOING   0x0
>> +#define PHYCTRL_FREQSEL_200M   0x0
>> +#define PHYCTRL_FREQSEL_50M    0x1
>> +#define PHYCTRL_FREQSEL_100M   0x2
>> +#define PHYCTRL_FREQSEL_150M   0x3
>> +#define PHYCTRL_FREQSEL_MASK   0x3
>> +#define PHYCTRL_FREQSEL_SHIFT  0xc
>> +#define PHYCTRL_DR_MASK                0x7
>> +#define PHYCTRL_DR_SHIFT       0x4
>> +#define PHYCTRL_DR_50OHM       0x0
>> +#define PHYCTRL_DR_33OHM       0x1
>> +#define PHYCTRL_DR_66OHM       0x2
>> +#define PHYCTRL_DR_100OHM      0x3
>> +#define PHYCTRL_DR_40OHM       0x4
>>
>>  struct rockchip_emmc_phy {
>>         unsigned int    reg_offset;
>> @@ -154,6 +167,20 @@ static int rockchip_emmc_phy_power_on(struct phy
>> *phy)
>>         struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
>>         int ret = 0;
>>
>> +       /* DLL operation: 170 to 200 MHz */
>
>
> What is 170 here? Should we expose them to dt instead of hardcoding
> them?

This was probably my fault.  I did some searching and found
<https://arasan.com/wp-content/media/eMMC-5-1-Total-Solution_Rev-1-3.pdf>.
It appears to be docs for a similar (but not identical) PHY.  We were
looking at it to try to get more clarity on some bits that were hard
to understand in the docs we had.

In that doc there appear to be 3 bits for selecting the DLL operation
and they have ranges defined.  In Rockchip's PHY there are only 2
bits.  Thus things don't map totally properly.

Anyway, comment should probably be removed.


I _think_ that this just needs to match the input clock rate of the
eMMC, right?  So presumably the PHY should get a reference to the same
clock that was given to the controller clock.  It can check the clock
at probe time and then register a notifier to keep the in sync (if we
expect the clock to change).

IMHO adding all of that complexity seems like it could wait for a
followup patch.  For now we can assume 200 MHz I think?


> Per the commit msg, signal may vary from board to board, so I guess
> 50ohm may not always be the best selection?

Starting out with something sane like 50 ohms seems like it makes
sense for now.  It's OK to start with a default for now to get things
basically working and then add device tree support once we have a
second user.


When we're ready to make this more generic, IMHO we might consider
having the PHY implement the pinctrl API and officially be a pin
controller and we use those bindings.  We are controlling pins so
using the pinctrl API seems like it might make sense?

I _think_ that perhaps what we're specifying here is actually slew
rate, but feel free to correct me if I'm wrong.  It looks as if "drive
strength" is supposed to be specified in terms of mA and the docs I
find show that we're actually controlling how fast the pins will
toggle.

I'm not 100% certain I know how the pinctrl bindings apply in this
case (maybe Heiko has ideas, or maybe we should send a proposal to
Linus W?), but from the bindings they look like they offer some
flexibility.

Maybe this would look like below (or maybe you need some extra sub-nodes)

       sdhci: sdhci at fe330000 {
               compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
               reg = <0x0 0xfe330000 0x0 0x10000>;
               interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
               clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
               clock-names = "clk_xin", "clk_ahb";
               assigned-clocks = <&cru SCLK_EMMC>;
               assigned-clock-rates = <200000000>;
               phys = <&emmc_phy>;
               phy-names = "phy_arasan";
               pinctrl-names = "default";
               pinctrl-0 = <&pcfg_emmc_slew_rate_x1_00>;
               status = "disabled";
       };

               emmc_phy: phy at f780 {
                       compatible = "rockchip,rk3399-emmc-phy";
                       reg = <0xf780 0x20>;
                       #phy-cells = <0>;
                       status = "disabled";

                       pcfg_emmc_slew_rate_x1_00: pcfg-emmc-slew-rate-x1-00 {
                               slew-rate = <100>;
                       };
                       pcfg_emmc_slew_rate_x1_50: pcfg-emmc-slew-rate-x1-50 {
                               slew-rate = <150>;
                       };
                       pcfg_emmc_slew_rate_x0_75: pcfg-emmc-slew-rate-x0-75 {
                               slew-rate = <75>;
                       };
                       pcfg_emmc_slew_rate_x0_50: pcfg-emmc-slew-rate-x0-50 {
                               slew-rate = <50>;
                       };
                       pcfg_emmc_slew_rate_x1_20: pcfg-emmc-slew-rate-x1-20 {
                               slew-rate = <120>;
                       };
                       pcfg_emmc_slew_rate_x1_20: pcfg-emmc-slew-rate-x1-20 {
                               slew-rate = <120>;
                       };
           };

The nice thing about using the pinctrl API is that:

* It allows us to _also_ control pullups / pulldowns.  We probably
want to control those also since some boards may use external pullups
and others may want to use the internal ones.

* If SDHCI needs to dynamically adjust things (like turning on pulls,
adjusting drive strengths, etc) it can do it in a sane API.



> Another thing I need to elaborate more here is that emmc phy only
> supports 50/100/150/200Mhz. Presumably people love to use the highest
> speed mode with its upper limiting frequency, but in case of some
> special requirement or bad board design, they want to add max-frequency
> in dts for emmc controller. In this case PHYCTRL_FREQSEL_XXXM should
> meet the actual max-frequency, take 100M for example, otherwise
> emmc_phy's  tuning block will use 200M to do some calculation but it
> certainly should be 100M. This leads emmc_phy to choose the wrong
> phase. Finally maybe you will see triggering re-tune easily or some
> worse case of even tuning failure when probing card.

Sounds like this should be handled as per above: make sure that the
PHY has access to the clock and can check it's rate.

---

So overall:

* Should re-spin and remove the comment about 170 MHz.

* I think this could land as-is other than the comment.

* Long term someone (hopefully at Rockchip) should think about making
the driver auto-adjust using the clock API.

* Long term someone (hopefully at Rockchip) should think about trying
to use the pinctrl API to allow adjusting drive strengths and pullups.


-Doug


From dianders at chromium.org  Fri May 13 12:43:25 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 12:43:25 -0700
Subject: [PATCH 1/2] clk: rockchip: mark rk3399 GIC clocks as critical
In-Reply-To: <1463164937-91089-1-git-send-email-briannorris@chromium.org>
References: <1463164937-91089-1-git-send-email-briannorris@chromium.org>
Message-ID: <CAD=FV=UjPy-n-53nhxr7yC1t1j+eD6pRt0_i5_6hhY=Rnz6xsw@mail.gmail.com>

Brian,

On Fri, May 13, 2016 at 11:42 AM, Brian Norris <briannorris at chromium.org> wrote:
> We never want to kill the GIC.
>
> Noticed when making other clock fixups, and seeing the newly-constructed
> clock tree try to disable cpll, where we had this parent structure:
>
>   aclk_gic <------\
>                   |--- aclk_gic_pre <-- cpll <-- pll_cpll
>   aclk_gic_noc <--/
>
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
>  drivers/clk/rockchip/clk-rk3399.c | 2 ++
>  1 file changed, 2 insertions(+)

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Fri May 13 13:10:57 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 13:10:57 -0700
Subject: [PATCH 2/2] clk: rockchip: fix incorrect parent for rk3399's {c,
 g}pll_aclk_perihp_src
In-Reply-To: <1463164937-91089-2-git-send-email-briannorris@chromium.org>
References: <1463164937-91089-1-git-send-email-briannorris@chromium.org>
 <1463164937-91089-2-git-send-email-briannorris@chromium.org>
Message-ID: <CAD=FV=XstYhqpStSGw5PObWvpsvd3Nwp_hfEE-56bpFoVUyu+g@mail.gmail.com>

Hi,

On Fri, May 13, 2016 at 11:42 AM, Brian Norris <briannorris at chromium.org> wrote:
> From: Xing Zheng <zhengxing at rock-chips.com>
>
> There was a typo, swapping 'c' <--> 'g'.
>
> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
>  drivers/clk/rockchip/clk-rk3399.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
> index 145756c4f3c8..9f86bfef70f7 100644
> --- a/drivers/clk/rockchip/clk-rk3399.c
> +++ b/drivers/clk/rockchip/clk-rk3399.c
> @@ -832,9 +832,9 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
>                         RK3399_CLKGATE_CON(13), 1, GFLAGS),
>
>         /* perihp */
> -       GATE(0, "cpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED,
> +       GATE(0, "cpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED,
>                         RK3399_CLKGATE_CON(5), 0, GFLAGS),
> -       GATE(0, "gpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED,
> +       GATE(0, "gpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED,
>                         RK3399_CLKGATE_CON(5), 1, GFLAGS),
>         COMPOSITE(ACLK_PERIHP, "aclk_perihp", mux_aclk_perihp_p, CLK_IGNORE_UNUSED,
>                         RK3399_CLKSEL_CON(14), 7, 1, MFLAGS, 0, 5, DFLAGS,

Definitely there was a bug since this table itself was inconsistent.
...and I _think_ this fix is correct, but I'll note that the TRM has
more inconsistency here.

In the big clock table 'CRU Clock Architecture Diagram', I see:
  CLK 4 is CPLL
  CLK 5 is GPLL
  CLK 125 is aclk_perihp_cpll_src and has 4 (CPLL) as source, with
g5[0] as the bit
  CLK 126 is aclk_perihp_gpll_src and has 5 (GPLL) as source, with
g5[1] as the bit

In the definition of CRU_CLKGATE_CON5:
  bit 0 shows aclk_perihp_gpll_src_en
  bit 1 shows aclk_perihp_cpll_src_en


Thus the table shows CPLL as gate5[0] and GPLL as gate5[1].  The
register definition shows the opposite.  I'll tend to believe the
table over the register definition, but I figured I'd bring it up
anyway.


Xing Zheng: can you confirm that the table is correct and ask
documentation folks to fix the register definition for
CRU_CLKGATE_CON5?



Thanks!

-Doug


From briannorris at chromium.org  Fri May 13 13:50:18 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 13:50:18 -0700
Subject: [PATCH] ARM64: dts: rockchip: assign default rates for core rk3399
 clocks
Message-ID: <1463172618-96001-1-git-send-email-briannorris@chromium.org>

From: Xing Zheng <zhengxing at rock-chips.com>

These clocks are all core clocks used by many blocks/peripherals, many
of whose drivers don't set their clock rates at all. Let's assign
reasonable default clock rates for these core clocks, so that these
peripherals get something reasonable by default, and also so that if
child devices want to select a clock rate themselves, their muxes have
some reasonable parent clock rates to branch off of (rather than just
the boot-time defaults).

This helps the eMMC PHY, for one, to get a reasonable ACLK rate.

Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
Signed-off-by: Brian Norris <briannorris at chromium.org>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a143b0..6fa9cc332482 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -478,6 +478,22 @@
 		reg = <0x0 0xff760000 0x0 0x1000>;
 		#clock-cells = <1>;
 		#reset-cells = <1>;
+		assigned-clocks =
+			<&cru PLL_GPLL>, <&cru PLL_CPLL>,
+			<&cru PLL_NPLL>,
+			<&cru ACLK_PERIHP>, <&cru HCLK_PERIHP>,
+			<&cru PCLK_PERIHP>,
+			<&cru ACLK_PERILP0>, <&cru HCLK_PERILP0>,
+			<&cru PCLK_PERILP0>,
+			<&cru HCLK_PERILP1>, <&cru PCLK_PERILP1>;
+		assigned-clock-rates =
+			 <594000000>,  <800000000>,
+			<1000000000>,
+			 <150000000>,   <75000000>,
+			  <37500000>,
+			 <100000000>,  <100000000>,
+			  <50000000>,
+			 <100000000>,   <50000000>;
 	};
 
 	grf: syscon at ff770000 {
-- 
2.8.0.rc3.226.g39d4020



From briannorris at chromium.org  Fri May 13 14:04:40 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 14:04:40 -0700
Subject: [PATCH 2/4] phy: rockchip-emmc: configure frequency range and
 drive impedance
In-Reply-To: <CAD=FV=UwocUy_bOUrJZB47taHWdV1KGkvi5CyZf74Y8cvGgVmw@mail.gmail.com>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
 <1463092986-61777-2-git-send-email-briannorris@chromium.org>
 <3695875b-09c3-cd80-3062-55d985e51f70@rock-chips.com>
 <CAD=FV=UwocUy_bOUrJZB47taHWdV1KGkvi5CyZf74Y8cvGgVmw@mail.gmail.com>
Message-ID: <20160513210440.GA99074@google.com>

On Fri, May 13, 2016 at 11:46:33AM -0700, Doug Anderson wrote:
> On Thu, May 12, 2016 at 6:02 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> > On 2016/5/13 6:43, Brian Norris wrote:
> >> @@ -154,6 +167,20 @@ static int rockchip_emmc_phy_power_on(struct phy
> >> *phy)
> >>         struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
> >>         int ret = 0;
> >>
> >> +       /* DLL operation: 170 to 200 MHz */
> >
> >
> > What is 170 here? Should we expose them to dt instead of hardcoding
> > them?
> 
> This was probably my fault.  I did some searching and found
> <https://arasan.com/wp-content/media/eMMC-5-1-Total-Solution_Rev-1-3.pdf>.
> It appears to be docs for a similar (but not identical) PHY.  We were
> looking at it to try to get more clarity on some bits that were hard
> to understand in the docs we had.
> 
> In that doc there appear to be 3 bits for selecting the DLL operation
> and they have ranges defined.  In Rockchip's PHY there are only 2
> bits.  Thus things don't map totally properly.
> 
> Anyway, comment should probably be removed.

[...]

> So overall:
> 
> * Should re-spin and remove the comment about 170 MHz.
> 
> * I think this could land as-is other than the comment.

Right, will fix the first bullet point.

Brian


From briannorris at chromium.org  Fri May 13 14:09:43 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 14:09:43 -0700
Subject: [PATCH v2 2/4] phy: rockchip-emmc: configure frequency range and
 drive impedance
In-Reply-To: <1463092986-61777-2-git-send-email-briannorris@chromium.org>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
 <1463092986-61777-2-git-send-email-briannorris@chromium.org>
Message-ID: <20160513210943.GB99074@google.com>

From: Shawn Lin <shawn.lin at rock-chips.com>

Signal integrity analysis has suggested we set these values. Do this in
power_on(), so that they get reconfigured after suspend/resume.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
Signed-off-by: Brian Norris <briannorris at chromium.org>
---
v2:
 * Sent only patch 2/4 with version 2, to avoid spamming; will move on to v3
   for all patches if I need to send another
 * Drop 170 MHz comment; this was only applicable to a subtly different Arasan
   PHY

 drivers/phy/phy-rockchip-emmc.c | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/drivers/phy/phy-rockchip-emmc.c b/drivers/phy/phy-rockchip-emmc.c
index 48cbe691a889..f2f75cf69af1 100644
--- a/drivers/phy/phy-rockchip-emmc.c
+++ b/drivers/phy/phy-rockchip-emmc.c
@@ -56,6 +56,19 @@
 #define PHYCTRL_DLLRDY_SHIFT	0x5
 #define PHYCTRL_DLLRDY_DONE	0x1
 #define PHYCTRL_DLLRDY_GOING	0x0
+#define PHYCTRL_FREQSEL_200M	0x0
+#define PHYCTRL_FREQSEL_50M	0x1
+#define PHYCTRL_FREQSEL_100M	0x2
+#define PHYCTRL_FREQSEL_150M	0x3
+#define PHYCTRL_FREQSEL_MASK	0x3
+#define PHYCTRL_FREQSEL_SHIFT	0xc
+#define PHYCTRL_DR_MASK		0x7
+#define PHYCTRL_DR_SHIFT	0x4
+#define PHYCTRL_DR_50OHM	0x0
+#define PHYCTRL_DR_33OHM	0x1
+#define PHYCTRL_DR_66OHM	0x2
+#define PHYCTRL_DR_100OHM	0x3
+#define PHYCTRL_DR_40OHM	0x4
 
 struct rockchip_emmc_phy {
 	unsigned int	reg_offset;
@@ -154,6 +167,20 @@ static int rockchip_emmc_phy_power_on(struct phy *phy)
 	struct rockchip_emmc_phy *rk_phy = phy_get_drvdata(phy);
 	int ret = 0;
 
+	/* DLL operation: 200 MHz */
+	regmap_write(rk_phy->reg_base,
+		     rk_phy->reg_offset + GRF_EMMCPHY_CON0,
+		     HIWORD_UPDATE(PHYCTRL_FREQSEL_200M,
+				   PHYCTRL_FREQSEL_MASK,
+				   PHYCTRL_FREQSEL_SHIFT));
+
+	/* Drive impedance: 50 Ohm */
+	regmap_write(rk_phy->reg_base,
+		     rk_phy->reg_offset + GRF_EMMCPHY_CON6,
+		     HIWORD_UPDATE(PHYCTRL_DR_50OHM,
+				   PHYCTRL_DR_MASK,
+				   PHYCTRL_DR_SHIFT));
+
 	/* Power up emmc phy analog blocks */
 	ret = rockchip_emmc_phy_power(rk_phy, PHYCTRL_PDB_PWR_ON);
 	if (ret)
-- 
2.8.0.rc3.226.g39d4020



From dianders at chromium.org  Fri May 13 14:20:42 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 14:20:42 -0700
Subject: [PATCH] ARM64: dts: rockchip: assign default rates for core
 rk3399 clocks
In-Reply-To: <1463172618-96001-1-git-send-email-briannorris@chromium.org>
References: <1463172618-96001-1-git-send-email-briannorris@chromium.org>
Message-ID: <CAD=FV=V+AmXzHmB06=Lp6w5wGBCYUgZr5gsbSKwsVSOTq=tNYw@mail.gmail.com>

Hi,

On Fri, May 13, 2016 at 1:50 PM, Brian Norris <briannorris at chromium.org> wrote:
> From: Xing Zheng <zhengxing at rock-chips.com>
>
> These clocks are all core clocks used by many blocks/peripherals, many
> of whose drivers don't set their clock rates at all. Let's assign
> reasonable default clock rates for these core clocks, so that these
> peripherals get something reasonable by default, and also so that if
> child devices want to select a clock rate themselves, their muxes have
> some reasonable parent clock rates to branch off of (rather than just
> the boot-time defaults).
>
> This helps the eMMC PHY, for one, to get a reasonable ACLK rate.
>
> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi | 16 ++++++++++++++++
>  1 file changed, 16 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> index 46f325a143b0..6fa9cc332482 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -478,6 +478,22 @@
>                 reg = <0x0 0xff760000 0x0 0x1000>;
>                 #clock-cells = <1>;
>                 #reset-cells = <1>;
> +               assigned-clocks =
> +                       <&cru PLL_GPLL>, <&cru PLL_CPLL>,
> +                       <&cru PLL_NPLL>,
> +                       <&cru ACLK_PERIHP>, <&cru HCLK_PERIHP>,
> +                       <&cru PCLK_PERIHP>,
> +                       <&cru ACLK_PERILP0>, <&cru HCLK_PERILP0>,
> +                       <&cru PCLK_PERILP0>,
> +                       <&cru HCLK_PERILP1>, <&cru PCLK_PERILP1>;
> +               assigned-clock-rates =
> +                        <594000000>,  <800000000>,
> +                       <1000000000>,
> +                        <150000000>,   <75000000>,
> +                         <37500000>,
> +                        <100000000>,  <100000000>,
> +                         <50000000>,
> +                        <100000000>,   <50000000>;

I agree that
* this is sane information to have in this node (like in rk3288)
* the rates look sane (similar to rk3288 but two are double)
* these rates match what I see in Rockchip's kernel

So:

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Fri May 13 14:42:06 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 14:42:06 -0700
Subject: [PATCH v2 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
In-Reply-To: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
References: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
Message-ID: <CAD=FV=UwtHu+DmJZqeWDQ8B9wMVdKODRignqDdZ4rknnmQru3g@mail.gmail.com>

Hi,

On Thu, May 12, 2016 at 3:35 PM, Brian Norris <briannorris at chromium.org> wrote:
> Add description for the SDHCI v5.1 eMMC controller on rk3399. Fix it to
> 200 MHz, to support all supported timing modes.
>
> Note that 'rockchip,rk3399-sdhci-5.1' is not documented; we presumably
> have a compliant Arasan controller, but let's have a rockchip property
> as the canonical backup/precautionary measure. Per Heiko's previous
> suggestion, let's not clutter the arasan doc with it.
>
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
> v2:
>
>  * improved commit message
>  * assign eMMC clock to 200 MHz
>
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi | 25 ++++++++++++++++++++++++-
>  1 file changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> index 46f325a143b0..9980c2eab4e9 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -215,6 +215,19 @@
>                 status = "disabled";
>         };
>
> +       sdhci: sdhci at fe330000 {
> +               compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
> +               reg = <0x0 0xfe330000 0x0 0x10000>;
> +               interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
> +               clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
> +               clock-names = "clk_xin", "clk_ahb";
> +               assigned-clocks = <&cru SCLK_EMMC>;
> +               assigned-clock-rates = <200000000>;
> +               phys = <&emmc_phy>;
> +               phy-names = "phy_arasan";
> +               status = "disabled";
> +       };
> +
>         usb_host0_ehci: usb at fe380000 {
>                 compatible = "generic-ehci";
>                 reg = <0x0 0xfe380000 0x0 0x20000>;
> @@ -481,8 +494,18 @@
>         };
>
>         grf: syscon at ff770000 {
> -               compatible = "rockchip,rk3399-grf", "syscon";
> +               compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
>                 reg = <0x0 0xff770000 0x0 0x10000>;
> +
> +               #address-cells = <1>;
> +               #size-cells = <1>;
> +
> +               emmc_phy: phy at f780 {
> +                       compatible = "rockchip,rk3399-emmc-phy";
> +                       reg = <0xf780 0x20>;

This is slightly wrong.  It should be:

reg = <0xf780 0x24>;

The status register is at an offset of 0x20 and is 4 bytes big, so we
need room for it.


After that is fixed, feel free to add my Reviewed-by tag.

-Doug


From briannorris at chromium.org  Fri May 13 14:47:24 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 14:47:24 -0700
Subject: [PATCH v3 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
Message-ID: <1463176045-109748-1-git-send-email-briannorris@chromium.org>

Add description for the SDHCI v5.1 eMMC controller on rk3399. Fix it to
200 MHz, to support all supported timing modes.

Note that 'rockchip,rk3399-sdhci-5.1' is not documented; we presumably
have a compliant Arasan controller, but let's have a rockchip property
as the canonical backup/precautionary measure. Per Heiko's previous
suggestion, let's not clutter the arasan doc with it.

Signed-off-by: Brian Norris <briannorris at chromium.org>
Reviewed-by: Doug Anderson <dianders at chromium.org>
Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>
---
v3:

 * correct emmc_phy reg length to 0x24

v2:

 * improved commit message
 * assign eMMC clock to 200 MHz


 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a143b0..99078f5ebeb9 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -215,6 +215,19 @@
 		status = "disabled";
 	};
 
+	sdhci: sdhci at fe330000 {
+		compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
+		reg = <0x0 0xfe330000 0x0 0x10000>;
+		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
+		clock-names = "clk_xin", "clk_ahb";
+		assigned-clocks = <&cru SCLK_EMMC>;
+		assigned-clock-rates = <200000000>;
+		phys = <&emmc_phy>;
+		phy-names = "phy_arasan";
+		status = "disabled";
+	};
+
 	usb_host0_ehci: usb at fe380000 {
 		compatible = "generic-ehci";
 		reg = <0x0 0xfe380000 0x0 0x20000>;
@@ -481,8 +494,18 @@
 	};
 
 	grf: syscon at ff770000 {
-		compatible = "rockchip,rk3399-grf", "syscon";
+		compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
 		reg = <0x0 0xff770000 0x0 0x10000>;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
+
+		emmc_phy: phy at f780 {
+			compatible = "rockchip,rk3399-emmc-phy";
+			reg = <0xf780 0x24>;
+			#phy-cells = <0>;
+			status = "disabled";
+		};
 	};
 
 	watchdog at ff840000 {
-- 
2.8.0.rc3.226.g39d4020



From briannorris at chromium.org  Fri May 13 14:47:25 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 14:47:25 -0700
Subject: [PATCH v3 2/2] ARM64: dts: rockchip: enable eMMC for rk3399 EVB
In-Reply-To: <1463176045-109748-1-git-send-email-briannorris@chromium.org>
References: <1463176045-109748-1-git-send-email-briannorris@chromium.org>
Message-ID: <1463176045-109748-2-git-send-email-briannorris@chromium.org>

Rockchip's rk3399 evaluation board has eMMC. Let's enable the
newly-added node.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
v3:

 * no change

v2:

 * better commit description

 arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
index 1a3eb1482050..0b27d91084c4 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
@@ -89,6 +89,18 @@
 	status = "okay";
 };
 
+&emmc_phy {
+	status = "okay";
+};
+
+&sdhci {
+	bus-width = <8>;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	non-removable;
+	status = "okay";
+};
+
 &uart2 {
 	status = "okay";
 };
-- 
2.8.0.rc3.226.g39d4020



From heiko at sntech.de  Fri May 13 14:47:57 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 13 May 2016 23:47:57 +0200
Subject: [PATCH v2 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
In-Reply-To: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
References: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
Message-ID: <5607915.FAWxOoA1QB@phil>

Am Donnerstag, 12. Mai 2016, 15:35:51 schrieb Brian Norris:
> Add description for the SDHCI v5.1 eMMC controller on rk3399. Fix it to
> 200 MHz, to support all supported timing modes.
> 
> Note that 'rockchip,rk3399-sdhci-5.1' is not documented; we presumably
> have a compliant Arasan controller, but let's have a rockchip property
> as the canonical backup/precautionary measure. Per Heiko's previous
> suggestion, let's not clutter the arasan doc with it.
> 
> Signed-off-by: Brian Norris <briannorris at chromium.org>

At least one split is necessary.
So please at least split out the simple-mfd addition into a separate patch
(I should've seen that in v1 already, but sadly didn't)

I'm undecided if the emmc-phy addition also should get its own patch, but I 
guess it can stay together with the emmc controller.

> ---
> v2:
> 
>  * improved commit message
>  * assign eMMC clock to 200 MHz
> 
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi | 25 ++++++++++++++++++++++++-
>  1 file changed, 24 insertions(+), 1 deletion(-)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index
> 46f325a143b0..9980c2eab4e9 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -215,6 +215,19 @@
>  		status = "disabled";
>  	};
> 
> +	sdhci: sdhci at fe330000 {
> +		compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
> +		reg = <0x0 0xfe330000 0x0 0x10000>;
> +		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
> +		clock-names = "clk_xin", "clk_ahb";
> +		assigned-clocks = <&cru SCLK_EMMC>;
> +		assigned-clock-rates = <200000000>;
> +		phys = <&emmc_phy>;
> +		phy-names = "phy_arasan";
> +		status = "disabled";
> +	};
> +
>  	usb_host0_ehci: usb at fe380000 {
>  		compatible = "generic-ehci";
>  		reg = <0x0 0xfe380000 0x0 0x20000>;
> @@ -481,8 +494,18 @@
>  	};
> 
>  	grf: syscon at ff770000 {
> -		compatible = "rockchip,rk3399-grf", "syscon";
> +		compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
>  		reg = <0x0 0xff770000 0x0 0x10000>;
> +
> +		#address-cells = <1>;
> +		#size-cells = <1>;
> +
> +		emmc_phy: phy at f780 {
> +			compatible = "rockchip,rk3399-emmc-phy";
> +			reg = <0xf780 0x20>;
> +			#phy-cells = <0>;
> +			status = "disabled";
> +		};
>  	};
> 
>  	watchdog at ff840000 {



From briannorris at chromium.org  Fri May 13 14:48:15 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 14:48:15 -0700
Subject: [PATCH v2 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
In-Reply-To: <CAD=FV=UwtHu+DmJZqeWDQ8B9wMVdKODRignqDdZ4rknnmQru3g@mail.gmail.com>
References: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
 <CAD=FV=UwtHu+DmJZqeWDQ8B9wMVdKODRignqDdZ4rknnmQru3g@mail.gmail.com>
Message-ID: <20160513214815.GA109473@google.com>

On Fri, May 13, 2016 at 02:42:06PM -0700, Doug Anderson wrote:
> On Thu, May 12, 2016 at 3:35 PM, Brian Norris <briannorris at chromium.org> wrote:
> > +               emmc_phy: phy at f780 {
> > +                       compatible = "rockchip,rk3399-emmc-phy";
> > +                       reg = <0xf780 0x20>;
> 
> This is slightly wrong.  It should be:
> 
> reg = <0xf780 0x24>;
> 
> The status register is at an offset of 0x20 and is 4 bytes big, so we
> need room for it.

Fixed.

> After that is fixed, feel free to add my Reviewed-by tag.

Done.

Thanks for the review.

Brian


From heiko at sntech.de  Fri May 13 14:49:52 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 13 May 2016 23:49:52 +0200
Subject: [PATCH v2 2/2] ARM64: dts: rockchip: enable eMMC for rk3399 EVB
In-Reply-To: <1463092552-60696-2-git-send-email-briannorris@chromium.org>
References: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
 <1463092552-60696-2-git-send-email-briannorris@chromium.org>
Message-ID: <1537214.5jQgtQP16t@phil>

Am Donnerstag, 12. Mai 2016, 15:35:52 schrieb Brian Norris:
> Rockchip's rk3399 evaluation board has eMMC. Let's enable the
> newly-added node.
> 
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
> v2:
> 
>  * better commit description
> 
>  arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 12 ++++++++++++
>  1 file changed, 12 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts index
> 1a3eb1482050..0b27d91084c4 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> +++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
> @@ -89,6 +89,18 @@
>  	status = "okay";
>  };
> 
> +&emmc_phy {
> +	status = "okay";
> +};

another thing I should've seen yesterday, emmc_phy should not be below the 
&pwm nodes (aka alphabetically please)


Heiko

> +&sdhci {
> +	bus-width = <8>;
> +	mmc-hs400-1_8v;
> +	mmc-hs400-enhanced-strobe;
> +	non-removable;
> +	status = "okay";
> +};
> +
>  &uart2 {
>  	status = "okay";
>  };



From briannorris at chromium.org  Fri May 13 14:57:24 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 14:57:24 -0700
Subject: [PATCH v2 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
In-Reply-To: <5607915.FAWxOoA1QB@phil>
References: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
 <5607915.FAWxOoA1QB@phil>
Message-ID: <20160513215724.GB109473@google.com>

On Fri, May 13, 2016 at 11:47:57PM +0200, Heiko Stuebner wrote:
> Am Donnerstag, 12. Mai 2016, 15:35:51 schrieb Brian Norris:
> > Add description for the SDHCI v5.1 eMMC controller on rk3399. Fix it to
> > 200 MHz, to support all supported timing modes.
> > 
> > Note that 'rockchip,rk3399-sdhci-5.1' is not documented; we presumably
> > have a compliant Arasan controller, but let's have a rockchip property
> > as the canonical backup/precautionary measure. Per Heiko's previous
> > suggestion, let's not clutter the arasan doc with it.
> > 
> > Signed-off-by: Brian Norris <briannorris at chromium.org>
> 
> At least one split is necessary.
> So please at least split out the simple-mfd addition into a separate patch

Will do.

BTW, should this be noted in
Documentation/devicetree/bindings/soc/rockchip/grf.txt now?

> (I should've seen that in v1 already, but sadly didn't)

No problem.

> I'm undecided if the emmc-phy addition also should get its own patch, but I 
> guess it can stay together with the emmc controller.

I think it makes sense for them to stay together. What's a phy without a
controller to use it? :)

Brian


From dianders at chromium.org  Fri May 13 15:01:56 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 15:01:56 -0700
Subject: [PATCH 1/4] phy: rockchip-emmc: give DLL some extra time to be
 ready
In-Reply-To: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
Message-ID: <CAD=FV=WxWz4wyFPJ=gt7bzQb-cvkASB2aRm+e-2wPrUQ6ZaSEw@mail.gmail.com>

Hi,

On Thu, May 12, 2016 at 3:43 PM, Brian Norris <briannorris at chromium.org> wrote:
> From: Shawn Lin <shawn.lin at rock-chips.com>
>
> According to the databook, 10.2us is the max time for dll to be ready to
> work. However in testing, some chips need 20us for dll to be ready. This
> patch adds some extra margin for dllrdy to be ready, fixing our
> -ETIMEDOUT issues.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
>  drivers/phy/phy-rockchip-emmc.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/phy/phy-rockchip-emmc.c b/drivers/phy/phy-rockchip-emmc.c
> index 6ebcf3e41c46..48cbe691a889 100644
> --- a/drivers/phy/phy-rockchip-emmc.c
> +++ b/drivers/phy/phy-rockchip-emmc.c
> @@ -119,10 +119,11 @@ static int rockchip_emmc_phy_power(struct rockchip_emmc_phy *rk_phy,
>                                    PHYCTRL_ENDLL_MASK,
>                                    PHYCTRL_ENDLL_SHIFT));
>         /*
> -        * After enable analog DLL circuits, we need extra 10.2us
> -        * for dll to be ready for work.
> +        * After enable analog DLL circuits, we need an extra 10.2us
> +        * for dll to be ready for work. But according to testing, we
> +        * find some chips need more than 25us.
>          */
> -       udelay(11);
> +       udelay(30);
>         regmap_read(rk_phy->reg_base,
>                     rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
>                     &dllrdy);

Seems sane.  This is a "random delay" but you've documented it well,
and an extra 19 microseconds won't be the end of the world.

If we truly trusted the "DLLRDY" bit we could actually do a loop here,
but it's probably not worth it...

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Fri May 13 15:04:53 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 15:04:53 -0700
Subject: [PATCH v2 2/4] phy: rockchip-emmc: configure frequency range and
 drive impedance
In-Reply-To: <20160513210943.GB99074@google.com>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
 <1463092986-61777-2-git-send-email-briannorris@chromium.org>
 <20160513210943.GB99074@google.com>
Message-ID: <CAD=FV=VyzaPEQvY57AF65VGzv600uBZT9jQy4N=s4Z_YPzphxw@mail.gmail.com>

Hi,

On Fri, May 13, 2016 at 2:09 PM, Brian Norris <briannorris at chromium.org> wrote:
> From: Shawn Lin <shawn.lin at rock-chips.com>
>
> Signal integrity analysis has suggested we set these values. Do this in
> power_on(), so that they get reconfigured after suspend/resume.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
> v2:
>  * Sent only patch 2/4 with version 2, to avoid spamming; will move on to v3
>    for all patches if I need to send another
>  * Drop 170 MHz comment; this was only applicable to a subtly different Arasan
>    PHY
>
>  drivers/phy/phy-rockchip-emmc.c | 27 +++++++++++++++++++++++++++
>  1 file changed, 27 insertions(+)

As per my comments on v1, this is a sane starting point and seems like
a good idea to land.  Hopefully someone at Rockchip can pick things up
and continue making this more configurable.

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From briannorris at chromium.org  Fri May 13 15:12:02 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 15:12:02 -0700
Subject: [PATCH v4 1/3] ARM64: dts: rockchip: make rk3399's grf a "simple-mfd"
Message-ID: <1463177524-113856-1-git-send-email-briannorris@chromium.org>

Per the examples in
Documentation/devicetree/bindings/phy/rockchip-emmc-phy.txt, we need the
grf node to be a simple-mfd in order to properly enumerate child devices
like our eMMC PHY.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
v4:

 * New, split out of patch 2, per Heiko's recommendation

 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a143b0..e1c3667a9bea 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -481,8 +481,11 @@
 	};
 
 	grf: syscon at ff770000 {
-		compatible = "rockchip,rk3399-grf", "syscon";
+		compatible = "rockchip,rk3399-grf", "syscon", "simple-mfd";
 		reg = <0x0 0xff770000 0x0 0x10000>;
+
+		#address-cells = <1>;
+		#size-cells = <1>;
 	};
 
 	watchdog at ff840000 {
-- 
2.8.0.rc3.226.g39d4020



From briannorris at chromium.org  Fri May 13 15:12:04 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 15:12:04 -0700
Subject: [PATCH v4 3/3] ARM64: dts: rockchip: enable eMMC for rk3399 EVB
In-Reply-To: <1463177524-113856-1-git-send-email-briannorris@chromium.org>
References: <1463177524-113856-1-git-send-email-briannorris@chromium.org>
Message-ID: <1463177524-113856-3-git-send-email-briannorris@chromium.org>

Rockchip's rk3399 evaluation board has eMMC. Let's enable the
newly-added nodes.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
v4:

 * alphabetize &node references

v3:

 * no change

v2:

 * better commit description

 arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
index 1a3eb1482050..d33aa06d46f5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
@@ -77,6 +77,10 @@
 	};
 };
 
+&emmc_phy {
+	status = "okay";
+};
+
 &pwm0 {
 	status = "okay";
 };
@@ -89,6 +93,14 @@
 	status = "okay";
 };
 
+&sdhci {
+	bus-width = <8>;
+	mmc-hs400-1_8v;
+	mmc-hs400-enhanced-strobe;
+	non-removable;
+	status = "okay";
+};
+
 &uart2 {
 	status = "okay";
 };
-- 
2.8.0.rc3.226.g39d4020



From briannorris at chromium.org  Fri May 13 15:12:03 2016
From: briannorris at chromium.org (Brian Norris)
Date: Fri, 13 May 2016 15:12:03 -0700
Subject: [PATCH v4 2/3] ARM64: dts: rockchip: add sdhci/emmc for rk3399
In-Reply-To: <1463177524-113856-1-git-send-email-briannorris@chromium.org>
References: <1463177524-113856-1-git-send-email-briannorris@chromium.org>
Message-ID: <1463177524-113856-2-git-send-email-briannorris@chromium.org>

Add description for the SDHCI v5.1 eMMC controller on rk3399. Fix it to
200 MHz, to support all supported timing modes.

Note that 'rockchip,rk3399-sdhci-5.1' is not documented; we presumably
have a compliant Arasan controller, but let's have a rockchip property
as the canonical backup/precautionary measure. Per Heiko's previous
suggestion, let's not clutter the arasan doc with it.

Signed-off-by: Brian Norris <briannorris at chromium.org>
---
v4:

 * split "simple-mfd" out into patch 1

v3:

 * correct emmc_phy reg length to 0x24

v2:

 * improved commit message
 * assign eMMC clock to 200 MHz

 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index e1c3667a9bea..99078f5ebeb9 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -215,6 +215,19 @@
 		status = "disabled";
 	};
 
+	sdhci: sdhci at fe330000 {
+		compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
+		reg = <0x0 0xfe330000 0x0 0x10000>;
+		interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
+		clock-names = "clk_xin", "clk_ahb";
+		assigned-clocks = <&cru SCLK_EMMC>;
+		assigned-clock-rates = <200000000>;
+		phys = <&emmc_phy>;
+		phy-names = "phy_arasan";
+		status = "disabled";
+	};
+
 	usb_host0_ehci: usb at fe380000 {
 		compatible = "generic-ehci";
 		reg = <0x0 0xfe380000 0x0 0x20000>;
@@ -486,6 +499,13 @@
 
 		#address-cells = <1>;
 		#size-cells = <1>;
+
+		emmc_phy: phy at f780 {
+			compatible = "rockchip,rk3399-emmc-phy";
+			reg = <0xf780 0x24>;
+			#phy-cells = <0>;
+			status = "disabled";
+		};
 	};
 
 	watchdog at ff840000 {
-- 
2.8.0.rc3.226.g39d4020



From heiko at sntech.de  Fri May 13 15:14:40 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 May 2016 00:14:40 +0200
Subject: [PATCH v2 1/2] ARM64: dts: rockchip: add sdhci/emmc for rk3399
In-Reply-To: <20160513215724.GB109473@google.com>
References: <1463092552-60696-1-git-send-email-briannorris@chromium.org>
 <5607915.FAWxOoA1QB@phil> <20160513215724.GB109473@google.com>
Message-ID: <1647746.RHuiZHceXs@phil>

Am Freitag, 13. Mai 2016, 14:57:24 schrieb Brian Norris:
> On Fri, May 13, 2016 at 11:47:57PM +0200, Heiko Stuebner wrote:
> > Am Donnerstag, 12. Mai 2016, 15:35:51 schrieb Brian Norris:
> > > Add description for the SDHCI v5.1 eMMC controller on rk3399. Fix it
> > > to
> > > 200 MHz, to support all supported timing modes.
> > > 
> > > Note that 'rockchip,rk3399-sdhci-5.1' is not documented; we presumably
> > > have a compliant Arasan controller, but let's have a rockchip property
> > > as the canonical backup/precautionary measure. Per Heiko's previous
> > > suggestion, let's not clutter the arasan doc with it.
> > > 
> > > Signed-off-by: Brian Norris <briannorris at chromium.org>
> > 
> > At least one split is necessary.
> > So please at least split out the simple-mfd addition into a separate
> > patch
> Will do.
> 
> BTW, should this be noted in
> Documentation/devicetree/bindings/soc/rockchip/grf.txt now?

The simple-mfd is already documented in mfd/mfd.txt in a general way, so I 
don't think every instance needs to have that, especially as it mainly 
affects sub-nodes alone.




From dianders at chromium.org  Fri May 13 15:25:30 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 15:25:30 -0700
Subject: [PATCH 3/4] phy: rockchip-emmc: configure default output tap delay
In-Reply-To: <1463092986-61777-3-git-send-email-briannorris@chromium.org>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
 <1463092986-61777-3-git-send-email-briannorris@chromium.org>
Message-ID: <CAD=FV=WupNv+z86BgmR1n8bj+b6GKA5Ew7U9hgoAxV9dxF7gjQ@mail.gmail.com>

Hi,

On Thu, May 12, 2016 at 3:43 PM, Brian Norris <briannorris at chromium.org> wrote:
> The output tap delay controls helps maintain the hold requirements for
> eMMC. The exact value is dependent on the SoC and other factors, though
> it isn't really an exact science. But the default of 0 is not very good,
> as it doesn't give the eMMC much hold time, so let's bump up to 4
> (approx 90 degree phase?). If we need to configure this any further
> (e.g., based on board or speed factors), we may need to consider a
> device tree representation.

As I understand it, this solves much the same problem as my patch in
<https://patchwork.kernel.org/patch/9085581/>, but for the eMMC port
on rk3399 (which doesn't use dw_mmc).  As argued in that patch and
also in the discussion from
<https://patchwork.kernel.org/patch/9030621/>, if we eventually end up
needing to put something in the device tree we need to be really
careful.  Specifically to get the exact right value here I think you
need to consider the input clock, speed mode, and any SoC-specific
delays differences between the clock and the data lines.  That would
imply that, if anything, the device tree data would only contain
information about the SoC-specific delay differences and all other
work to set this value would involve coordination between the PHY and
the SDHCI controller.


However, as also discussed previously, we don't appear to need to be
very exact about the value here.  It seems like setting this to 4 (~90
degrees?) is a much better starting point than leaving it at the
default of 0.


...so I'd be all for landing this patch.  Perhaps Shawn can chime in
and confirm that our understanding is correct and possibly we can
update the commit message.  Then presumably someone at Rockchip can
keep working to find a better way to set this long term.

Sound good?


-Doug


From dianders at chromium.org  Fri May 13 15:26:37 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 15:26:37 -0700
Subject: [PATCH 4/4] phy: rockchip-emmc: reindent the register definitions
In-Reply-To: <1463092986-61777-4-git-send-email-briannorris@chromium.org>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
 <1463092986-61777-4-git-send-email-briannorris@chromium.org>
Message-ID: <CAD=FV=XkJTrUD-+KBCoZkzyN9_XRH+uE=AjEiVvaNf5iad=jow@mail.gmail.com>

Hi,

On Thu, May 12, 2016 at 3:43 PM, Brian Norris <briannorris at chromium.org> wrote:
> Some of the spacing was wrong (spaces instead of tabs), and due to
> longer entries added later, the columns weren't aligned. Let's get
> everything consistent.
>
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
>  drivers/phy/phy-rockchip-emmc.c | 76 ++++++++++++++++++++---------------------
>  1 file changed, 38 insertions(+), 38 deletions(-)

Sure, why not?

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Fri May 13 15:53:14 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 15:53:14 -0700
Subject: [PATCH v4 1/3] ARM64: dts: rockchip: make rk3399's grf a
 "simple-mfd"
In-Reply-To: <1463177524-113856-1-git-send-email-briannorris@chromium.org>
References: <1463177524-113856-1-git-send-email-briannorris@chromium.org>
Message-ID: <CAD=FV=UGbNsneP_Vm_YYOrjWYn=zVKB5pZYvOOJczKAuRztCkw@mail.gmail.com>

Hi,

On Fri, May 13, 2016 at 3:12 PM, Brian Norris <briannorris at chromium.org> wrote:
> Per the examples in
> Documentation/devicetree/bindings/phy/rockchip-emmc-phy.txt, we need the
> grf node to be a simple-mfd in order to properly enumerate child devices
> like our eMMC PHY.
>
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
> v4:
>
>  * New, split out of patch 2, per Heiko's recommendation
>
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Fri May 13 15:54:35 2016
From: dianders at chromium.org (Doug Anderson)
Date: Fri, 13 May 2016 15:54:35 -0700
Subject: [PATCH v4 3/3] ARM64: dts: rockchip: enable eMMC for rk3399 EVB
In-Reply-To: <1463177524-113856-3-git-send-email-briannorris@chromium.org>
References: <1463177524-113856-1-git-send-email-briannorris@chromium.org>
 <1463177524-113856-3-git-send-email-briannorris@chromium.org>
Message-ID: <CAD=FV=VffvTEVyCpVn20rRsGRYKPVy_6qjTBoiOvMX4EjeWFrQ@mail.gmail.com>

Hi,

On Fri, May 13, 2016 at 3:12 PM, Brian Norris <briannorris at chromium.org> wrote:
> Rockchip's rk3399 evaluation board has eMMC. Let's enable the
> newly-added nodes.
>
> Signed-off-by: Brian Norris <briannorris at chromium.org>
> ---
> v4:
>
>  * alphabetize &node references
>
> v3:
>
>  * no change
>
> v2:
>
>  * better commit description
>
>  arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 12 ++++++++++++
>  1 file changed, 12 insertions(+)

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From zhengxing at rock-chips.com  Fri May 13 20:36:14 2016
From: zhengxing at rock-chips.com (Xing Zheng)
Date: Sat, 14 May 2016 11:36:14 +0800
Subject: [PATCH 2/2] clk: rockchip: fix incorrect parent for rk3399's
 {c,g}pll_aclk_perihp_src
In-Reply-To: <CAD=FV=XstYhqpStSGw5PObWvpsvd3Nwp_hfEE-56bpFoVUyu+g@mail.gmail.com>
References: <1463164937-91089-1-git-send-email-briannorris@chromium.org>
 <1463164937-91089-2-git-send-email-briannorris@chromium.org>
 <CAD=FV=XstYhqpStSGw5PObWvpsvd3Nwp_hfEE-56bpFoVUyu+g@mail.gmail.com>
Message-ID: <57369D2E.3030002@rock-chips.com>

Hi Doug,

On 2016?05?14? 04:10, Doug Anderson wrote:
> Hi,
>
> On Fri, May 13, 2016 at 11:42 AM, Brian Norris <briannorris at chromium.org> wrote:
>> From: Xing Zheng <zhengxing at rock-chips.com>
>>
>> There was a typo, swapping 'c' <--> 'g'.
>>
>> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
>> Signed-off-by: Brian Norris <briannorris at chromium.org>
>> ---
>>   drivers/clk/rockchip/clk-rk3399.c | 4 ++--
>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
>> index 145756c4f3c8..9f86bfef70f7 100644
>> --- a/drivers/clk/rockchip/clk-rk3399.c
>> +++ b/drivers/clk/rockchip/clk-rk3399.c
>> @@ -832,9 +832,9 @@ static struct rockchip_clk_branch rk3399_clk_branches[] __initdata = {
>>                          RK3399_CLKGATE_CON(13), 1, GFLAGS),
>>
>>          /* perihp */
>> -       GATE(0, "cpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED,
>> +       GATE(0, "cpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED,
>>                          RK3399_CLKGATE_CON(5), 0, GFLAGS),
>> -       GATE(0, "gpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED,
>> +       GATE(0, "gpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED,
>>                          RK3399_CLKGATE_CON(5), 1, GFLAGS),
>>          COMPOSITE(ACLK_PERIHP, "aclk_perihp", mux_aclk_perihp_p, CLK_IGNORE_UNUSED,
>>                          RK3399_CLKSEL_CON(14), 7, 1, MFLAGS, 0, 5, DFLAGS,
> Definitely there was a bug since this table itself was inconsistent.
> ...and I _think_ this fix is correct, but I'll note that the TRM has
> more inconsistency here.
>
> In the big clock table 'CRU Clock Architecture Diagram', I see:
>    CLK 4 is CPLL
>    CLK 5 is GPLL
>    CLK 125 is aclk_perihp_cpll_src and has 4 (CPLL) as source, with
> g5[0] as the bit
>    CLK 126 is aclk_perihp_gpll_src and has 5 (GPLL) as source, with
> g5[1] as the bit
>
> In the definition of CRU_CLKGATE_CON5:
>    bit 0 shows aclk_perihp_gpll_src_en
>    bit 1 shows aclk_perihp_cpll_src_en
>
>
> Thus the table shows CPLL as gate5[0] and GPLL as gate5[1].  The
> register definition shows the opposite.  I'll tend to believe the
> table over the register definition, but I figured I'd bring it up
> anyway.
>
>
> Xing Zheng: can you confirm that the table is correct and ask
> documentation folks to fix the register definition for
> CRU_CLKGATE_CON5?
Yes, previously, our IC & DOC partner confirmed that the definition of 
CRU_CLKGATE_CON5 should be:
   bit 0 shows aclk_perihp_cpll_src_en
   bit 1 shows aclk_perihp_gpll_src_en

Sorry to the incorrect register definition, we will fix them and review 
the TRM again.

Thanks.

-- 
- Xing Zheng




From heiko at sntech.de  Sat May 14 04:30:41 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 May 2016 13:30:41 +0200
Subject: [PATCH v9 0/8] add i2c driver supported for rk3399
In-Reply-To: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
References: <1463039586-8134-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1649653.55gUf8lt1c@phil>

Am Donnerstag, 12. Mai 2016, 15:52:58 schrieb David Wu:
> There are three points differert from others:
>  - new method to caculate i2c timings for rk3399
>  - pclk and function clk are separated at rk3399
>  - add fast-plus mode supported for rk3399

On a rk3288

Tested-by: Heiko Stuebner <heiko at sntech.de>

to make sure nothing currently working broke - and everything is running 
still fine.


Heiko


From heiko at sntech.de  Sat May 14 04:57:12 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 May 2016 13:57:12 +0200
Subject: [PATCH] ARM64: dts: rockchip: assign default rates for core
 rk3399 clocks
In-Reply-To: <1463172618-96001-1-git-send-email-briannorris@chromium.org>
References: <1463172618-96001-1-git-send-email-briannorris@chromium.org>
Message-ID: <25672526.OH6Oxq7zkd@phil>

Am Freitag, 13. Mai 2016, 13:50:18 schrieb Brian Norris:
> From: Xing Zheng <zhengxing at rock-chips.com>
> 
> These clocks are all core clocks used by many blocks/peripherals, many
> of whose drivers don't set their clock rates at all. Let's assign
> reasonable default clock rates for these core clocks, so that these
> peripherals get something reasonable by default, and also so that if
> child devices want to select a clock rate themselves, their muxes have
> some reasonable parent clock rates to branch off of (rather than just
> the boot-time defaults).
> 
> This helps the eMMC PHY, for one, to get a reasonable ACLK rate.
> 
> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
> Signed-off-by: Brian Norris <briannorris at chromium.org>

applied for 4.8 with Doug's review-tag (after making the ARM64 lower-case)


From wsy2220 at gmail.com  Sat May 14 09:16:02 2016
From: wsy2220 at gmail.com (Shuyu Wei)
Date: Sun, 15 May 2016 00:16:02 +0800
Subject: [PATCH] ethernet:arc: Fix racing of TX ring buffer
Message-ID: <20160514161602.GA3347@debian-dorm>

The tail of the ring buffer(txbd_dirty) should never go ahead of the
head(txbd_curr) or the ring buffer will corrupt. 

This is the root cause of racing.

Besides, setting the FOR_EMAC flag should be the last step of modifying
the buffer descriptor, or possible racing will occur.

Signed-off-by: Shuyu Wei <sy.w at outlook.com>
---

diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index a3a9392..5ece05b 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -155,7 +155,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)
        struct net_device_stats *stats = &ndev->stats;
        unsigned int i;
 
-       for (i = 0; i < TX_BD_NUM; i++) {
+       for (i = priv->txbd_dirty; i != priv->txbd_curr; i = (i + 1) % TX_BD_NUM) {
                unsigned int *txbd_dirty = &priv->txbd_dirty;
                struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
                struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
@@ -686,12 +686,12 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
 
        skb_tx_timestamp(skb);
 
+       priv->tx_buff[*txbd_curr].skb = skb;
        *info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
        /* Make sure info word is set */
        wmb();
 
-       priv->tx_buff[*txbd_curr].skb = skb;
 
        /* Increment index to point to the next BD */
        *txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;



From heiko at sntech.de  Sat May 14 10:01:23 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 May 2016 19:01:23 +0200
Subject: [PATCH v4 1/3] ARM64: dts: rockchip: make rk3399's grf a
 "simple-mfd"
In-Reply-To: <1463177524-113856-1-git-send-email-briannorris@chromium.org>
References: <1463177524-113856-1-git-send-email-briannorris@chromium.org>
Message-ID: <2246118.hzaJHK3UnE@phil>

Am Freitag, 13. Mai 2016, 15:12:02 schrieb Brian Norris:
> Per the examples in
> Documentation/devicetree/bindings/phy/rockchip-emmc-phy.txt, we need the
> grf node to be a simple-mfd in order to properly enumerate child devices
> like our eMMC PHY.
> 
> Signed-off-by: Brian Norris <briannorris at chromium.org>

applied all 3 for 4.8 with the received Reviews.

Please keep the arm64 lower-case and carry over already received 
Acks/Reviews (Shawn and Doug on patch2 in v2).


Thanks
Heiko


From romieu at fr.zoreil.com  Sat May 14 13:03:56 2016
From: romieu at fr.zoreil.com (Francois Romieu)
Date: Sat, 14 May 2016 22:03:56 +0200
Subject: [PATCH] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160514161602.GA3347@debian-dorm>
References: <20160514161602.GA3347@debian-dorm>
Message-ID: <20160514200356.GA14105@electric-eye.fr.zoreil.com>

Shuyu Wei <wsy2220 at gmail.com> :
> The tail of the ring buffer(txbd_dirty) should never go ahead of the
> head(txbd_curr) or the ring buffer will corrupt. 
> 
> This is the root cause of racing.

No (see below).

It may suffer from some barrier illness though.

> Besides, setting the FOR_EMAC flag should be the last step of modifying
> the buffer descriptor, or possible racing will occur.

(s/Besides//)

Yes. Good catch.

> Signed-off-by: Shuyu Wei <sy.w at outlook.com>
> ---
> 
> diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
> index a3a9392..5ece05b 100644
> --- a/drivers/net/ethernet/arc/emac_main.c
> +++ b/drivers/net/ethernet/arc/emac_main.c
> @@ -155,7 +155,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>         struct net_device_stats *stats = &ndev->stats;
>         unsigned int i;
>  
> -       for (i = 0; i < TX_BD_NUM; i++) {
> +       for (i = priv->txbd_dirty; i != priv->txbd_curr; i = (i + 1) % TX_BD_NUM) {
>                 unsigned int *txbd_dirty = &priv->txbd_dirty;
>                 struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
>                 struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];

"i" is only used as a loop counter in arc_emac_tx_clean. It is not even
used as an index to dereference an array or whatever. Only "priv->txbd_dirty"
is used.

arc_emac_tx_clean() checks FOR_EMAC, skb, and dirty tx data. It takes care of
clearing those itself. Thus, (memory / io barrier considerations apart) it can
only proceed beyond its own "if ((info & FOR_EMAC) || !txbd->data || !skb)"
check if arc_emac_tx wrote all of those.

Where they are used as loop counters, both TX_BD_NUM and txbd_curr - txbd_dirty
can be considered as hints (please note that unsigned arithmetic can replace
the "%" sludgehammer here).

> @@ -686,12 +686,12 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
>  
>         skb_tx_timestamp(skb);

> +       priv->tx_buff[*txbd_curr].skb = skb;

	dma_wmb();

(sync writes to memory before releasing descriptor)

>         *info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
>  
>         /* Make sure info word is set */
>         wmb();

arc_emac_tx_clean can run from this point.

txbd_curr is still not set (and it does need to). So, if you insist
on txbd_curr appearing in arc_emac_tx_clean::for(...), it's perfectly
possible to ignore a sent packet.

I ignored arc_reg_set() at the end of arc_emac_tx(). I have no idea
if it is posted nor if it forces the chipset to read the descriptors
(synchronously ?) so part of the sentence above could be wrong.

You have found a big offender in arc_emac_tx() but the arc_emac_tx_clean()
part is imho useless, incorrectly understood or misworded.

-- 
Ueimor


From heiko at sntech.de  Sat May 14 13:19:43 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 14 May 2016 22:19:43 +0200
Subject: [PATCH] iommu/rockchip: fix zap cache during device attach
In-Reply-To: <20160510155046.24515-1-john@metanate.com>
References: <20160510155046.24515-1-john@metanate.com>
Message-ID: <11003810.ccjcAXkzhi@phil>

Am Dienstag, 10. Mai 2016, 16:50:46 schrieb John Keeping:
> rk_iommu_command() takes a struct rk_iommu and iterates over the slave
> MMUs, so this is doubly wrong in that we're passing in the wrong pointer
> and talking to MMUs that we shouldn't be.
> 
> Fixes: cd6438c5f844 ("iommu/rockchip: Reconstruct to support multi
> slaves") Signed-off-by: John Keeping <john at metanate.com>

on a rk3288-veyron
Tested-by: Heiko Stuebner <heiko at sntech.de>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>

I was wondering for a short time why this didn't spew warnings until I 
realized that the iommu->bases[i] is of course a void* .


Heiko


From wsy2220 at gmail.com  Sat May 14 16:10:44 2016
From: wsy2220 at gmail.com (Shuyu Wei)
Date: Sun, 15 May 2016 07:10:44 +0800
Subject: [PATCH] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160514200356.GA14105@electric-eye.fr.zoreil.com>
References: <20160514161602.GA3347@debian-dorm>
 <20160514200356.GA14105@electric-eye.fr.zoreil.com>
Message-ID: <20160514231044.GA2968@debian-dorm>

On Sat, May 14, 2016 at 10:03:56PM +0200, Francois Romieu wrote:
> Shuyu Wei <wsy2220 at gmail.com> :
> > The tail of the ring buffer(txbd_dirty) should never go ahead of the
> > head(txbd_curr) or the ring buffer will corrupt. 
> > 
> > This is the root cause of racing.
> 
> No (see below).
> 
> It may suffer from some barrier illness though.
> 
> > Besides, setting the FOR_EMAC flag should be the last step of modifying
> > the buffer descriptor, or possible racing will occur.
> 
> (s/Besides//)
> 
> Yes. Good catch.
> 
> > Signed-off-by: Shuyu Wei <sy.w at outlook.com>
> > ---
> > 
> > diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
> > index a3a9392..5ece05b 100644
> > --- a/drivers/net/ethernet/arc/emac_main.c
> > +++ b/drivers/net/ethernet/arc/emac_main.c
> > @@ -155,7 +155,7 @@ static void arc_emac_tx_clean(struct net_device *ndev)
> >         struct net_device_stats *stats = &ndev->stats;
> >         unsigned int i;
> >  
> > -       for (i = 0; i < TX_BD_NUM; i++) {
> > +       for (i = priv->txbd_dirty; i != priv->txbd_curr; i = (i + 1) % TX_BD_NUM) {
> >                 unsigned int *txbd_dirty = &priv->txbd_dirty;
> >                 struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
> >                 struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
> 
> "i" is only used as a loop counter in arc_emac_tx_clean. It is not even
> used as an index to dereference an array or whatever. Only "priv->txbd_dirty"
> is used.
> 
> arc_emac_tx_clean() checks FOR_EMAC, skb, and dirty tx data. It takes care of
> clearing those itself. Thus, (memory / io barrier considerations apart) it can
> only proceed beyond its own "if ((info & FOR_EMAC) || !txbd->data || !skb)"
> check if arc_emac_tx wrote all of those.
> 
> Where they are used as loop counters, both TX_BD_NUM and txbd_curr - txbd_dirty
> can be considered as hints (please note that unsigned arithmetic can replace
> the "%" sludgehammer here).
> 
> > @@ -686,12 +686,12 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
> >  
> >         skb_tx_timestamp(skb);
> 
> > +       priv->tx_buff[*txbd_curr].skb = skb;
> 
> 	dma_wmb();
> 
> (sync writes to memory before releasing descriptor)
> 
> >         *info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
> >  
> >         /* Make sure info word is set */
> >         wmb();
> 
> arc_emac_tx_clean can run from this point.
> 
> txbd_curr is still not set (and it does need to). So, if you insist
> on txbd_curr appearing in arc_emac_tx_clean::for(...), it's perfectly
> possible to ignore a sent packet.
> 
> I ignored arc_reg_set() at the end of arc_emac_tx(). I have no idea
> if it is posted nor if it forces the chipset to read the descriptors
> (synchronously ?) so part of the sentence above could be wrong.
> 
> You have found a big offender in arc_emac_tx() but the arc_emac_tx_clean()
> part is imho useless, incorrectly understood or misworded.
> 
> -- 
> Ueimor


Hi, Ueimor. Thanks for your reply.

I don't think taking txbd_curr and txbd_dirty only as hints is a good idea.
That could be a big waste, since tx_clean have to go through all the txbds.
I tried your advice, Tx throughput can only reach 5.52MB/s.

Leaving one sent packet in tx_clean is acceptable if we respect to txbd_curr
and txbd_dirty, since the ignored packet will be cleaned when new packets
arrive.

>  for (i = priv->txbd_dirty; i != priv->txbd_curr; i = (i + 1) % TX_BD_NUM) {
In fact, the loop above will always ignore one or two sent packet, the loop
below can free all packets or leave one if txbd_curr is not updated. I
use the above one since it is clearer.

  for (i = priv->txbd_dirty; (i + 1) % TX_BD_NUM != priv->txbd_curr; i = (i + 1) % TX_BD_NUM) {


From wsy2220 at gmail.com  Sat May 14 16:24:01 2016
From: wsy2220 at gmail.com (Shuyu Wei)
Date: Sun, 15 May 2016 07:24:01 +0800
Subject: [PATCH] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160514231044.GA2968@debian-dorm>
References: <20160514161602.GA3347@debian-dorm>
 <20160514200356.GA14105@electric-eye.fr.zoreil.com>
 <20160514231044.GA2968@debian-dorm>
Message-ID: <20160514232401.GB2968@debian-dorm>

Sorry, the last two lines is wrong, ignore it.

I mean I intended to ignore one or two packets.
It's just a trade-off for performance, but it
doesn't cause any memory leak.


From romieu at fr.zoreil.com  Sun May 15 02:19:53 2016
From: romieu at fr.zoreil.com (Francois Romieu)
Date: Sun, 15 May 2016 11:19:53 +0200
Subject: [PATCH] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160514231044.GA2968@debian-dorm>
References: <20160514161602.GA3347@debian-dorm>
 <20160514200356.GA14105@electric-eye.fr.zoreil.com>
 <20160514231044.GA2968@debian-dorm>
Message-ID: <20160515091953.GA19983@electric-eye.fr.zoreil.com>

Shuyu Wei <wsy2220 at gmail.com> :
[...]
> I don't think taking txbd_curr and txbd_dirty only as hints is a good idea.
> That could be a big waste, since tx_clean have to go through all the txbds.

Sorry if my point was not clear: arc_emac_tx_clean() does not need
to change (at least not for the reason given in the commit message) :o)

Current code:

static void arc_emac_tx_clean(struct net_device *ndev)
{
[...]
        for (i = 0; i < TX_BD_NUM; i++) {
                unsigned int *txbd_dirty = &priv->txbd_dirty;
                struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
                struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
                struct sk_buff *skb = tx_buff->skb;
                unsigned int info = le32_to_cpu(txbd->info);

                if ((info & FOR_EMAC) || !txbd->data || !skb)
                        break;
                        ^^^^^

-> the "break" statement prevents reading all txbds. At most one extra
   descriptor is read and this driver isn't in the Mpps business.

> I tried your advice, Tx throughput can only reach 5.52MB/s.

Even with the original code above ?

> Leaving one sent packet in tx_clean is acceptable if we respect to txbd_curr
> and txbd_dirty, since the ignored packet will be cleaned when new packets
> arrive.

There is no reason to leave tx packet roting in the first place. Really.
I doubt it would help bql for one.

Packet may rot because of unexpected hardware behavior and driver should
cope with it when it is diagnosed, sure. However, you don't want the driver
to opens it own unbounded window. Next packet: 10 us, 10 ms, 10 s ?

-- 
Ueimor


From john at metanate.com  Sun May 15 04:16:39 2016
From: john at metanate.com (John Keeping)
Date: Sun, 15 May 2016 12:16:39 +0100
Subject: [PATCH] iommu/rockchip: fix zap cache during device attach
In-Reply-To: <11003810.ccjcAXkzhi@phil>
References: <20160510155046.24515-1-john@metanate.com>
 <11003810.ccjcAXkzhi@phil>
Message-ID: <20160515111638.GA9715@river>

On Sat, May 14, 2016 at 10:19:43PM +0200, Heiko Stuebner wrote:
> Am Dienstag, 10. Mai 2016, 16:50:46 schrieb John Keeping:
> > rk_iommu_command() takes a struct rk_iommu and iterates over the slave
> > MMUs, so this is doubly wrong in that we're passing in the wrong pointer
> > and talking to MMUs that we shouldn't be.
> > 
> > Fixes: cd6438c5f844 ("iommu/rockchip: Reconstruct to support multi
> > slaves") Signed-off-by: John Keeping <john at metanate.com>
> 
> on a rk3288-veyron
> Tested-by: Heiko Stuebner <heiko at sntech.de>
> Reviewed-by: Heiko Stuebner <heiko at sntech.de>
> 
> I was wondering for a short time why this didn't spew warnings until I 
> realized that the iommu->bases[i] is of course a void* .

Yes, although sparse catches it because iommu->bases[i] is __iomem so it
shows up as a namespace warning.


From wsy2220 at gmail.com  Sun May 15 05:38:29 2016
From: wsy2220 at gmail.com (Shuyu Wei)
Date: Sun, 15 May 2016 20:38:29 +0800
Subject: [PATCH] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160515091953.GA19983@electric-eye.fr.zoreil.com>
References: <20160514161602.GA3347@debian-dorm>
 <20160514200356.GA14105@electric-eye.fr.zoreil.com>
 <20160514231044.GA2968@debian-dorm>
 <20160515091953.GA19983@electric-eye.fr.zoreil.com>
Message-ID: <20160515123829.GA2831@debian-dorm>

On Sun, May 15, 2016 at 11:19:53AM +0200, Francois Romieu wrote:
> 
> static void arc_emac_tx_clean(struct net_device *ndev)
> {
> [...]
>         for (i = 0; i < TX_BD_NUM; i++) {
>                 unsigned int *txbd_dirty = &priv->txbd_dirty;
>                 struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
>                 struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
>                 struct sk_buff *skb = tx_buff->skb;
>                 unsigned int info = le32_to_cpu(txbd->info);
> 
>                 if ((info & FOR_EMAC) || !txbd->data || !skb)
>                         break;
>                         ^^^^^
> 
> -> the "break" statement prevents reading all txbds. At most one extra
>    descriptor is read and this driver isn't in the Mpps business.
> 

You are right, I forgot the break statement.

> > I tried your advice, Tx throughput can only reach 5.52MB/s.
> 
> Even with the original code above ?

Yes, I left tx_clean unmodified, and took your advice below.
I tested it again just now, this time throughput do reach 9.8MB/s,
Maybe last time cpu is not idle.

I still have a question, is it possible that tx_clean() run
between   priv->tx_buff[*txbd_curr].skb = skb   and   dma_wmb()?

--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -685,13 +685,15 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
        wmb();
 
        skb_tx_timestamp(skb);
+       priv->tx_buff[*txbd_curr].skb = skb;
+
+       dma_wmb();
 
        *info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
        /* Make sure info word is set */
        wmb();
 
-       priv->tx_buff[*txbd_curr].skb = skb;
 
        /* Increment index to point to the next BD */
        *txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;



From romieu at fr.zoreil.com  Sun May 15 11:07:34 2016
From: romieu at fr.zoreil.com (Francois Romieu)
Date: Sun, 15 May 2016 20:07:34 +0200
Subject: [PATCH] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160515123829.GA2831@debian-dorm>
References: <20160514161602.GA3347@debian-dorm>
 <20160514200356.GA14105@electric-eye.fr.zoreil.com>
 <20160514231044.GA2968@debian-dorm>
 <20160515091953.GA19983@electric-eye.fr.zoreil.com>
 <20160515123829.GA2831@debian-dorm>
Message-ID: <20160515180734.GA23253@electric-eye.fr.zoreil.com>

Shuyu Wei <wsy2220 at gmail.com> :
[...]
> I still have a question, is it possible that tx_clean() run
> between   priv->tx_buff[*txbd_curr].skb = skb   and   dma_wmb()?

A (previous) run can take place after priv->tx_buff[*txbd_curr].skb and
before *info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len).

So, yes, the driver must check in arc_emac_tx_clean() that 1) either
txbd_dirty != txbd_curr or 2) "info" is not consistent with a still-not-used
status word. Please be patient with me and get rid of the useless "i"

diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index a3a9392..337ea3b 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -153,9 +153,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 {
 	struct arc_emac_priv *priv = netdev_priv(ndev);
 	struct net_device_stats *stats = &ndev->stats;
-	unsigned int i;
 
-	for (i = 0; i < TX_BD_NUM; i++) {
+	while (priv->txbd_dirty != priv->txbd_curr) {
 		unsigned int *txbd_dirty = &priv->txbd_dirty;
 		struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
 		struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];

-- 
Ueimor


From heiko at sntech.de  Sun May 15 15:06:31 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 16 May 2016 00:06:31 +0200
Subject: [PATCH v2 4/5] ARM: dts: rockchip: Add shared file for audio
 related nodes for veyron boards
In-Reply-To: <1462790795-25345-5-git-send-email-enric.balletbo@collabora.com>
References: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
 <1462790795-25345-5-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1769207.YFf2RsNhBy@phil>

Am Montag, 9. Mai 2016, 12:46:34 schrieb Enric Balletbo i Serra:
> Set i2s block to "okay", add sound node for max98090 with gpios for
> HP and Mic detect and pinctrl, and add a max98090 device and ts3a227e to
> the correct i2c bus.
> 
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>

I only got a "applied" reply from Marks scripts for patch 3/5, so only today
saw that all 3 actually got applied.

Anyway, I've applied this to my dts32-branch for 4.8 now [0] with some
modifications regarding
- the commit subject+message
- ordering
- io_domains access (via the phandle now)
- regulator suspend property
so maybe take a look and holler if you see a mistake.

I was able to get audio over the headphones (so definitly an improvement),
but so far not over the built-in speakers. Did you need to do something
special in the configuration for this?


Heiko

[0] https://git.kernel.org/cgit/linux/kernel/git/mmind/linux-rockchip.git/commit/?h=volatile-v4.8-armsoc/dts32&id=1452aee5a7acc03518ef5215dd3dbac4444efe52

> ---
> Changes since v1:
>  - None
> 
>  arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi | 102
> ++++++++++++++++++++++ 1 file changed, 102 insertions(+)
>  create mode 100644 arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
> 
> diff --git a/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
> b/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi new file mode 100644
> index 0000000..f045e1a
> --- /dev/null
> +++ b/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
> @@ -0,0 +1,102 @@
> +/*
> + * Google Veyron (and derivatives) fragment for the  max98090 audio
> + * codec and analog headphone jack.
> + *
> + * Copyright 2016 Google, Inc
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +/ {
> +
> +	sound {
> +		compatible = "rockchip,rockchip-audio-max98090";
> +		rockchip,model = "ROCKCHIP-I2S";
> +		rockchip,i2s-controller = <&i2s>;
> +		rockchip,audio-codec = <&max98090>;
> +		rockchip,hp-det-gpios = <&gpio6 5 GPIO_ACTIVE_HIGH>;
> +		rockchip,mic-det-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
> +		rockchip,headset-codec = <&headsetcodec>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&mic_det>, <&hp_det>;
> +	};
> +
> +	io-domains {
> +		audio-supply = <&vcc18_codec>;
> +	};
> +};
> +
> +&rk808 {
> +	vcc10-supply = <&vcc33_sys>;
> +
> +	regulators {
> +		vcc18_codec: LDO_REG6 {
> +			regulator-always-on;
> +			regulator-boot-on;
> +			regulator-min-microvolt = <1800000>;
> +			regulator-max-microvolt = <1800000>;
> +			regulator-name = "vcc18_codec";
> +			regulator-suspend-mem-disabled;
> +		};
> +	};
> +};
> +
> +&i2c2 {
> +	max98090: max98090 at 10 {
> +		compatible = "maxim,max98090";
> +		reg = <0x10>;
> +		clock-names = "mclk";
> +		clocks = <&cru SCLK_I2S0_OUT>;
> +		interrupt-parent = <&gpio6>;
> +		interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&int_codec>;
> +	};
> +};
> +
> +&i2c4 {
> +	headsetcodec: ts3a227e at 3b {
> +		compatible = "ti,ts3a227e";
> +		reg = <0x3b>;
> +		interrupt-parent = <&gpio0>;
> +		interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&ts3a227e_int_l>;
> +		ti,micbias = <7>;		/* MICBIAS = 2.8V */
> +	};
> +};
> +
> +&i2s {
> +	status = "okay";
> +	clock-names = "i2s_hclk", "i2s_clk";
> +	clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
> +};
> +
> +&pinctrl {
> +	codec {
> +		hp_det: hp-det {
> +			rockchip,pins = <6 5 RK_FUNC_GPIO &pcfg_pull_up>;
> +		};
> +
> +		/*
> +		 * HACK: We're going to _pull down_ this _active low_ interrupt
> +		 * so that it never fires.  We don't need this interrupt because
> +		 * we've got a ts3a227e chip but the driver requires it.
> +		 */
> +		int_codec: int-codec {
> +			rockchip,pins = <6 7 RK_FUNC_GPIO &pcfg_pull_down>;
> +		};
> +
> +		mic_det: mic-det {
> +			rockchip,pins = <6 11 RK_FUNC_GPIO &pcfg_pull_up>;
> +		};
> +	};
> +
> +	headset {
> +		ts3a227e_int_l: ts3a227e-int-l {
> +			rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_up>;
> +		};
> +	};
> +};



From heiko at sntech.de  Sun May 15 15:06:55 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 16 May 2016 00:06:55 +0200
Subject: [PATCH v2 5/5] ARM: dts: rockchip: veyron: Add analog audio
 codecs.
In-Reply-To: <1462790795-25345-6-git-send-email-enric.balletbo@collabora.com>
References: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
 <1462790795-25345-6-git-send-email-enric.balletbo@collabora.com>
Message-ID: <1769207.eXVA7j6895@phil>

Am Montag, 9. Mai 2016, 12:46:35 schrieb Enric Balletbo i Serra:
> Add analog-audio functionality for Veyron devices.
> 
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>

applied for 4.8


Thanks
Heiko


From shawn.lin at rock-chips.com  Sun May 15 21:15:29 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Mon, 16 May 2016 12:15:29 +0800
Subject: [PATCH 3/4] phy: rockchip-emmc: configure default output tap delay
In-Reply-To: <CAD=FV=WupNv+z86BgmR1n8bj+b6GKA5Ew7U9hgoAxV9dxF7gjQ@mail.gmail.com>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
 <1463092986-61777-3-git-send-email-briannorris@chromium.org>
 <CAD=FV=WupNv+z86BgmR1n8bj+b6GKA5Ew7U9hgoAxV9dxF7gjQ@mail.gmail.com>
Message-ID: <52567d92-d1d3-f089-65c2-a30f3a00386b@rock-chips.com>

Hi Doug,

On 2016/5/14 6:25, Doug Anderson wrote:
> Hi,
>
> On Thu, May 12, 2016 at 3:43 PM, Brian Norris <briannorris at chromium.org> wrote:
>> The output tap delay controls helps maintain the hold requirements for
>> eMMC. The exact value is dependent on the SoC and other factors, though
>> it isn't really an exact science. But the default of 0 is not very good,
>> as it doesn't give the eMMC much hold time, so let's bump up to 4
>> (approx 90 degree phase?). If we need to configure this any further
>> (e.g., based on board or speed factors), we may need to consider a
>> device tree representation.
>
> As I understand it, this solves much the same problem as my patch in
> <https://patchwork.kernel.org/patch/9085581/>, but for the eMMC port
> on rk3399 (which doesn't use dw_mmc).  As argued in that patch and
> also in the discussion from
> <https://patchwork.kernel.org/patch/9030621/>, if we eventually end up
> needing to put something in the device tree we need to be really
> careful.  Specifically to get the exact right value here I think you
> need to consider the input clock, speed mode, and any SoC-specific
> delays differences between the clock and the data lines.  That would
> imply that, if anything, the device tree data would only contain
> information about the SoC-specific delay differences and all other
> work to set this value would involve coordination between the PHY and
> the SDHCI controller.
>
>
> However, as also discussed previously, we don't appear to need to be
> very exact about the value here.  It seems like setting this to 4 (~90
> degrees?) is a much better starting point than leaving it at the
> default of 0.

The value, 4, is based on real silicon test observed from the
oscilloscope, and of course it meets the requirement of speed modes.
For arasan't phy, its phase is very accurate, so the real timing of
the value you set almost won't vary too much for different Socs.

So explicitly assigning 4 here looks sane currently except for crazy
PCB layout...


>
>
> ...so I'd be all for landing this patch.  Perhaps Shawn can chime in
> and confirm that our understanding is correct and possibly we can
> update the commit message.  Then presumably someone at Rockchip can
> keep working to find a better way to set this long term.
>
> Sound good?
>
>
> -Doug
>
>
>


-- 
Best Regards
Shawn Lin



From david.wu at rock-chips.com  Mon May 16 06:57:35 2016
From: david.wu at rock-chips.com (David Wu)
Date: Mon, 16 May 2016 21:57:35 +0800
Subject: [PATCH v10 0/8] add i2c driver supported for rk3399
Message-ID: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>

There are three points differert from others:
 - new method to caculate i2c timings for rk3399
 - pclk and function clk are separated at rk3399
 - add fast-plus mode supported for rk3399

David Wu (8):
  i2c: rk3x: add documentation to fields in "struct rk3x_i2c"
  i2c: rk3x: use struct "rk3x_i2c_calced_timings"
  i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
  i2c: rk3x: Change SoC data to not use array
  i2c: rk3x: Move spec timing data to "static const" structs
  dt-bindings: i2c: rk3x: add support for rk3399
  i2c: rk3x: add i2c support for rk3399 soc
  i2c: rk3x: support fast-mode plus for rk3399

 Documentation/devicetree/bindings/i2c/i2c-rk3x.txt |  16 +-
 drivers/i2c/busses/i2c-rk3x.c                      | 498 +++++++++++++++++----
 2 files changed, 434 insertions(+), 80 deletions(-)

-- 
1.9.1




From david.wu at rock-chips.com  Mon May 16 06:57:36 2016
From: david.wu at rock-chips.com (David Wu)
Date: Mon, 16 May 2016 21:57:36 +0800
Subject: [PATCH v10 1/8] i2c: rk3x: add documentation to fields in "struct
 rk3x_i2c"
In-Reply-To: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
References: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463407063-41218-2-git-send-email-david.wu@rock-chips.com>

Add kernel-doc documentation for the elements of the previously
undocumented struct rk3x_i2c.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Tested-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v10:
- none

Change in v9:
- add commit description.

Change in v8:
- none

 drivers/i2c/busses/i2c-rk3x.c | 22 +++++++++++++++++++++-
 1 file changed, 21 insertions(+), 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 80bed02..7e45d51 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -90,6 +90,26 @@ struct rk3x_i2c_soc_data {
 	int grf_offset;
 };
 
+/**
+ * struct rk3x_i2c - private data of the controller
+ * @adap: corresponding I2C adapter
+ * @dev: device for this controller
+ * @soc_data: related soc data struct
+ * @regs: virtual memory area
+ * @clk: clock of i2c bus
+ * @clk_rate_nb: i2c clk rate change notify
+ * @t: I2C known timing information
+ * @lock: spinlock for the i2c bus
+ * @wait: the waitqueue to wait for i2c transfer
+ * @busy: the condition for the event to wait for
+ * @msg: current i2c message
+ * @addr: addr of i2c slave device
+ * @mode: mode of i2c transfer
+ * @is_last_msg: flag determines whether it is the last msg in this transfer
+ * @state: state of i2c transfer
+ * @processed: byte length which has been send or received
+ * @error: error code for i2c transfer
+ */
 struct rk3x_i2c {
 	struct i2c_adapter adap;
 	struct device *dev;
@@ -116,7 +136,7 @@ struct rk3x_i2c {
 
 	/* I2C state machine */
 	enum rk3x_i2c_state state;
-	unsigned int processed; /* sent/received bytes */
+	unsigned int processed;
 	int error;
 };
 
-- 
1.9.1




From david.wu at rock-chips.com  Mon May 16 06:57:37 2016
From: david.wu at rock-chips.com (David Wu)
Date: Mon, 16 May 2016 21:57:37 +0800
Subject: [PATCH v10 2/8] i2c: rk3x: use struct "rk3x_i2c_calced_timings"
In-Reply-To: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
References: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463407063-41218-3-git-send-email-david.wu@rock-chips.com>

The "div_high" and "div_low" values are always used together.
Group them into a structure to make it easier to pass them
both around. This structure also provides a place for future
calculated timings.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
Tested-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v10:
- none

Change in v9:
- none

Change in v8:
- add commit description.

 drivers/i2c/busses/i2c-rk3x.c | 55 +++++++++++++++++++++++++------------------
 1 file changed, 32 insertions(+), 23 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 7e45d51..1e2677a 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -75,6 +75,16 @@ enum {
 #define WAIT_TIMEOUT      1000 /* ms */
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
+/**
+ * struct rk3x_i2c_calced_timings:
+ * @div_low: Divider output for low
+ * @div_high: Divider output for high
+ */
+struct rk3x_i2c_calced_timings {
+	unsigned long div_low;
+	unsigned long div_high;
+};
+
 enum rk3x_i2c_state {
 	STATE_IDLE,
 	STATE_START,
@@ -454,9 +464,8 @@ out:
  * Calculate divider values for desired SCL frequency
  *
  * @clk_rate: I2C input clock rate
- * @t: Known I2C timing information.
- * @div_low: Divider output for low
- * @div_high: Divider output for high
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
  *
  * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
  * a best-effort divider value is returned in divs. If the target rate is
@@ -464,8 +473,7 @@ out:
  */
 static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 			      struct i2c_timings *t,
-			      unsigned long *div_low,
-			      unsigned long *div_high)
+			      struct rk3x_i2c_calced_timings *t_calc)
 {
 	unsigned long spec_min_low_ns, spec_min_high_ns;
 	unsigned long spec_setup_start, spec_max_data_hold_ns;
@@ -572,8 +580,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 		 * Time needed to meet hold requirements is important.
 		 * Just use that.
 		 */
-		*div_low = min_low_div;
-		*div_high = min_high_div;
+		t_calc->div_low = min_low_div;
+		t_calc->div_high = min_high_div;
 	} else {
 		/*
 		 * We've got to distribute some time among the low and high
@@ -602,25 +610,25 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 
 		/* Give low the "ideal" and give high whatever extra is left */
 		extra_low_div = ideal_low_div - min_low_div;
-		*div_low = ideal_low_div;
-		*div_high = min_high_div + (extra_div - extra_low_div);
+		t_calc->div_low = ideal_low_div;
+		t_calc->div_high = min_high_div + (extra_div - extra_low_div);
 	}
 
 	/*
 	 * Adjust to the fact that the hardware has an implicit "+1".
 	 * NOTE: Above calculations always produce div_low > 0 and div_high > 0.
 	 */
-	*div_low = *div_low - 1;
-	*div_high = *div_high - 1;
+	t_calc->div_low--;
+	t_calc->div_high--;
 
 	/* Maximum divider supported by hw is 0xffff */
-	if (*div_low > 0xffff) {
-		*div_low = 0xffff;
+	if (t_calc->div_low > 0xffff) {
+		t_calc->div_low = 0xffff;
 		ret = -EINVAL;
 	}
 
-	if (*div_high > 0xffff) {
-		*div_high = 0xffff;
+	if (t_calc->div_high > 0xffff) {
+		t_calc->div_high = 0xffff;
 		ret = -EINVAL;
 	}
 
@@ -630,19 +638,21 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 {
 	struct i2c_timings *t = &i2c->t;
-	unsigned long div_low, div_high;
+	struct rk3x_i2c_calced_timings calc;
 	u64 t_low_ns, t_high_ns;
 	int ret;
 
-	ret = rk3x_i2c_calc_divs(clk_rate, t, &div_low, &div_high);
+	ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
 	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
 
 	clk_enable(i2c->clk);
-	i2c_writel(i2c, (div_high << 16) | (div_low & 0xffff), REG_CLKDIV);
+	i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
+		   REG_CLKDIV);
 	clk_disable(i2c->clk);
 
-	t_low_ns = div_u64(((u64)div_low + 1) * 8 * 1000000000, clk_rate);
-	t_high_ns = div_u64(((u64)div_high + 1) * 8 * 1000000000, clk_rate);
+	t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
+	t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
+			    clk_rate);
 	dev_dbg(i2c->dev,
 		"CLK %lukhz, Req %uns, Act low %lluns high %lluns\n",
 		clk_rate / 1000,
@@ -672,12 +682,11 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
 {
 	struct clk_notifier_data *ndata = data;
 	struct rk3x_i2c *i2c = container_of(nb, struct rk3x_i2c, clk_rate_nb);
-	unsigned long div_low, div_high;
+	struct rk3x_i2c_calced_timings calc;
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
-		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t,
-				       &div_low, &div_high) != 0)
+		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0)
 			return NOTIFY_STOP;
 
 		/* scale up */
-- 
1.9.1




From david.wu at rock-chips.com  Mon May 16 06:57:38 2016
From: david.wu at rock-chips.com (David Wu)
Date: Mon, 16 May 2016 21:57:38 +0800
Subject: [PATCH v10 3/8] i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
In-Reply-To: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
References: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463407063-41218-4-git-send-email-david.wu@rock-chips.com>

rk3x_i2c_setup() gets called directly before rk3x_i2c_start(),
and the last thing in setup was to clean the IPD, so no reason
to do it at the beginning of start.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Tested-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v10:
- none

Change in v9:
- modify commit message

Change in v8:
- none

 drivers/i2c/busses/i2c-rk3x.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 1e2677a..9eeb4e5 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -174,7 +174,6 @@ static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
 	u32 val;
 
-	rk3x_i2c_clean_ipd(i2c);
 	i2c_writel(i2c, REG_INT_START, REG_IEN);
 
 	/* enable adapter with correct mode, send START condition */
-- 
1.9.1




From david.wu at rock-chips.com  Mon May 16 06:57:39 2016
From: david.wu at rock-chips.com (David Wu)
Date: Mon, 16 May 2016 21:57:39 +0800
Subject: [PATCH v10 4/8] i2c: rk3x: Change SoC data to not use array
In-Reply-To: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
References: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463407063-41218-5-git-send-email-david.wu@rock-chips.com>

Specifying the i2c SoC data in an array provides very little benefit and
gets unwieldly / confusing as the array grows since the next bit of code
needs to refer to elements in the array by their raw integral index.

Let's just create a single 'static const' structure for each SoC so that
we can refer to these structures by ID.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Suggested-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
Tested-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v10:
- none

Change in v9:
- none

Change in v8:
- add commit description.

 drivers/i2c/busses/i2c-rk3x.c | 38 ++++++++++++++++++++++++++++++--------
 1 file changed, 30 insertions(+), 8 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 9eeb4e5..d7a871f 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -864,17 +864,39 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
 	.functionality		= rk3x_i2c_func,
 };
 
-static struct rk3x_i2c_soc_data soc_data[3] = {
-	{ .grf_offset = 0x154 }, /* rk3066 */
-	{ .grf_offset = 0x0a4 }, /* rk3188 */
-	{ .grf_offset = -1 },    /* no I2C switching needed */
+static const struct rk3x_i2c_soc_data rk3066_soc_data = {
+	.grf_offset = 0x154,
+};
+
+static const struct rk3x_i2c_soc_data rk3188_soc_data = {
+	.grf_offset = 0x0a4,
+};
+
+static const struct rk3x_i2c_soc_data rk3228_soc_data = {
+	.grf_offset = -1,
+};
+
+static const struct rk3x_i2c_soc_data rk3288_soc_data = {
+	.grf_offset = -1,
 };
 
 static const struct of_device_id rk3x_i2c_match[] = {
-	{ .compatible = "rockchip,rk3066-i2c", .data = (void *)&soc_data[0] },
-	{ .compatible = "rockchip,rk3188-i2c", .data = (void *)&soc_data[1] },
-	{ .compatible = "rockchip,rk3228-i2c", .data = (void *)&soc_data[2] },
-	{ .compatible = "rockchip,rk3288-i2c", .data = (void *)&soc_data[2] },
+	{
+		.compatible = "rockchip,rk3066-i2c",
+		.data = (void *)&rk3066_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3188-i2c",
+		.data = (void *)&rk3188_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3228-i2c",
+		.data = (void *)&rk3228_soc_data
+	},
+	{
+		.compatible = "rockchip,rk3288-i2c",
+		.data = (void *)&rk3288_soc_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
-- 
1.9.1




From david.wu at rock-chips.com  Mon May 16 07:03:24 2016
From: david.wu at rock-chips.com (David Wu)
Date: Mon, 16 May 2016 22:03:24 +0800
Subject: [PATCH v10 5/8] i2c: rk3x: Move spec timing data to "static const"
 structs
In-Reply-To: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
References: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463407404-41370-1-git-send-email-david.wu@rock-chips.com>

The i2c timing specs are really just constant data. There's no reason
to write code to init them, so move them out to structures. This not
only is a cleaner solution but it will reduce code duplication when we
introduce a new variant of rk3x_i2c_calc_divs() in a future patch.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Suggested-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
Tested-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v10:
- none

Change in v9:
- none

Changes in v8:
- add commit description.
- remove the spec values that were not needed, then
  introduce the additional values in the rk3399 patch. 

 drivers/i2c/busses/i2c-rk3x.c | 83 ++++++++++++++++++++++++++++---------------
 1 file changed, 55 insertions(+), 28 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index d7a871f..9791797 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -76,6 +76,34 @@ enum {
 #define DEFAULT_SCL_RATE  (100 * 1000) /* Hz */
 
 /**
+ * struct i2c_spec_values:
+ * @min_low_ns: min LOW period of the SCL clock
+ * @min_high_ns: min HIGH period of the SCL cloc
+ * @min_setup_start_ns: min set-up time for a repeated START conditio
+ * @max_data_hold_ns: max data hold time
+ */
+struct i2c_spec_values {
+	unsigned long min_low_ns;
+	unsigned long min_high_ns;
+	unsigned long min_setup_start_ns;
+	unsigned long max_data_hold_ns;
+};
+
+static const struct i2c_spec_values standard_mode_spec = {
+	.min_low_ns = 4700,
+	.min_high_ns = 4000,
+	.min_setup_start_ns = 4700,
+	.max_data_hold_ns = 3450,
+};
+
+static const struct i2c_spec_values fast_mode_spec = {
+	.min_low_ns = 1300,
+	.min_high_ns = 600,
+	.min_setup_start_ns = 600,
+	.max_data_hold_ns = 900,
+};
+
+/**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
  * @div_high: Divider output for high
@@ -460,6 +488,21 @@ out:
 }
 
 /**
+ * Get timing values of I2C specification
+ *
+ * @speed: Desired SCL frequency
+ *
+ * Returns: Matched i2c spec values.
+ */
+static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
+{
+	if (speed <= 100000)
+		return &standard_mode_spec;
+	else
+		return &fast_mode_spec;
+}
+
+/**
  * Calculate divider values for desired SCL frequency
  *
  * @clk_rate: I2C input clock rate
@@ -474,10 +517,6 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 			      struct i2c_timings *t,
 			      struct rk3x_i2c_calced_timings *t_calc)
 {
-	unsigned long spec_min_low_ns, spec_min_high_ns;
-	unsigned long spec_setup_start, spec_max_data_hold_ns;
-	unsigned long data_hold_buffer_ns;
-
 	unsigned long min_low_ns, min_high_ns;
 	unsigned long max_low_ns, min_total_ns;
 
@@ -489,6 +528,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	unsigned long min_div_for_hold, min_total_div;
 	unsigned long extra_div, extra_low_div, ideal_low_div;
 
+	unsigned long data_hold_buffer_ns = 50;
+	const struct i2c_spec_values *spec;
 	int ret = 0;
 
 	/* Only support standard-mode and fast-mode */
@@ -511,22 +552,8 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	 *	 This is because the i2c host on Rockchip holds the data line
 	 *	 for half the low time.
 	 */
-	if (t->bus_freq_hz <= 100000) {
-		/* Standard-mode */
-		spec_min_low_ns = 4700;
-		spec_setup_start = 4700;
-		spec_min_high_ns = 4000;
-		spec_max_data_hold_ns = 3450;
-		data_hold_buffer_ns = 50;
-	} else {
-		/* Fast-mode */
-		spec_min_low_ns = 1300;
-		spec_setup_start = 600;
-		spec_min_high_ns = 600;
-		spec_max_data_hold_ns = 900;
-		data_hold_buffer_ns = 50;
-	}
-	min_high_ns = t->scl_rise_ns + spec_min_high_ns;
+	spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+	min_high_ns = t->scl_rise_ns + spec->min_high_ns;
 
 	/*
 	 * Timings for repeated start:
@@ -536,14 +563,14 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	 * We need to account for those rules in picking our "high" time so
 	 * we meet tSU;STA and tHD;STA times.
 	 */
-	min_high_ns = max(min_high_ns,
-		DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start) * 1000, 875));
-	min_high_ns = max(min_high_ns,
-		DIV_ROUND_UP((t->scl_rise_ns + spec_setup_start +
-			      t->sda_fall_ns + spec_min_high_ns), 2));
-
-	min_low_ns = t->scl_fall_ns + spec_min_low_ns;
-	max_low_ns = spec_max_data_hold_ns * 2 - data_hold_buffer_ns;
+	min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+		(t->scl_rise_ns + spec->min_setup_start_ns) * 1000, 875));
+	min_high_ns = max(min_high_ns, DIV_ROUND_UP(
+		(t->scl_rise_ns + spec->min_setup_start_ns + t->sda_fall_ns +
+		spec->min_high_ns), 2));
+
+	min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+	max_low_ns =  spec->max_data_hold_ns * 2 - data_hold_buffer_ns;
 	min_total_ns = min_low_ns + min_high_ns;
 
 	/* Adjust to avoid overflow */
-- 
1.9.1




From david.wu at rock-chips.com  Mon May 16 07:04:12 2016
From: david.wu at rock-chips.com (David Wu)
Date: Mon, 16 May 2016 22:04:12 +0800
Subject: [PATCH v10 6/8] dt-bindings: i2c: rk3x: add support for rk3399
In-Reply-To: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
References: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463407452-41418-1-git-send-email-david.wu@rock-chips.com>

The bus clock and function clock are separated at rk3399,
and others use one clock as the bus clock and function clock.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Tested-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v10:
- none

Change in v9:
- remove unnecessary "REQUIRED".

Change in v8:
- remove error description.

 Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 16 +++++++++++++---
 1 file changed, 13 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
index 0b4a85f..bbc5a1e 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-rk3x.txt
@@ -6,10 +6,20 @@ RK3xxx SoCs.
 Required properties :
 
  - reg : Offset and length of the register set for the device
- - compatible : should be "rockchip,rk3066-i2c", "rockchip,rk3188-i2c",
-		"rockchip,rk3228-i2c" or "rockchip,rk3288-i2c".
+ - compatible: should be one of the following:
+   - "rockchip,rk3066-i2c": for rk3066
+   - "rockchip,rk3188-i2c": for rk3188
+   - "rockchip,rk3228-i2c": for rk3228
+   - "rockchip,rk3288-i2c": for rk3288
+   - "rockchip,rk3399-i2c": for rk3399
  - interrupts : interrupt number
- - clocks : parent clock
+ - clocks: See ../clock/clock-bindings.txt
+   - For older hardware (rk3066, rk3188, rk3228, rk3288):
+     - There is one clock that's used both to derive the functional clock
+       for the device and as the bus clock.
+   - For newer hardware (rk3399): specified by name
+     - "i2c": This is used to derive the functional clock.
+     - "pclk": This is the bus clock.
 
 Required on RK3066, RK3188 :
 
-- 
1.9.1




From david.wu at rock-chips.com  Mon May 16 07:05:03 2016
From: david.wu at rock-chips.com (David Wu)
Date: Mon, 16 May 2016 22:05:03 +0800
Subject: [PATCH v10 7/8] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
References: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463407503-41466-1-git-send-email-david.wu@rock-chips.com>

- new method to caculate i2c timings for rk3399:
  There was an timing issue about "repeated start" time at the I2C
  controller of version0, controller appears to drop SDA at .875x (7/8)
  programmed clk high. On version 1 of the controller, the rule(.875x)
  isn't enough to meet tSU;STA
  requirements on 100k's Standard-mode. To resolve this issue,
  sda_update_config, start_setup_config and stop_setup_config for I2C
  timing information are added, new rules are designed to calculate
  the timing information at new v1.
- pclk and function clk are separated at rk3399

Signed-off-by: David Wu <david.wu at rock-chips.com>
Tested-by: Caesar Wang <wxt at rock-chips.com>
Tested-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v10:
- fix the clean of con register in rk3x_i2c_stop()

Change in v9:
- add spin lock for tuning updated in rk3x_i2c_adapt_div() (Doug) 

Changes in v8:
- update tuning in RKI2C_CON register by doing a read-modify-write (Doug)
- new method to use pclk and clk (Doug)

Changes in v7:
- transform into a 9 series patches (Doug)
- drop highspeed with mastercode, and support fast-mode plus (Doug)

 drivers/i2c/busses/i2c-rk3x.c | 294 +++++++++++++++++++++++++++++++++++++++---
 1 file changed, 274 insertions(+), 20 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index 9791797..a96b516 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -58,6 +58,12 @@ enum {
 #define REG_CON_LASTACK   BIT(5) /* 1: send NACK after last received byte */
 #define REG_CON_ACTACK    BIT(6) /* 1: stop if NACK is received */
 
+#define REG_CON_TUNING_MASK GENMASK(15, 8)
+
+#define REG_CON_SDA_CFG(cfg) ((cfg) << 8)
+#define REG_CON_STA_CFG(cfg) ((cfg) << 12)
+#define REG_CON_STO_CFG(cfg) ((cfg) << 14)
+
 /* REG_MRXADDR bits */
 #define REG_MRXADDR_VALID(x) BIT(24 + (x)) /* [x*8+7:x*8] of MRX[R]ADDR valid */
 
@@ -77,40 +83,62 @@ enum {
 
 /**
  * struct i2c_spec_values:
+ * @min_hold_start_ns: min hold time (repeated) START condition
  * @min_low_ns: min LOW period of the SCL clock
  * @min_high_ns: min HIGH period of the SCL cloc
  * @min_setup_start_ns: min set-up time for a repeated START conditio
  * @max_data_hold_ns: max data hold time
+ * @min_data_setup_ns: min data set-up time
+ * @min_setup_stop_ns: min set-up time for STOP condition
+ * @min_hold_buffer_ns: min bus free time between a STOP and
+ * START condition
  */
 struct i2c_spec_values {
+	unsigned long min_hold_start_ns;
 	unsigned long min_low_ns;
 	unsigned long min_high_ns;
 	unsigned long min_setup_start_ns;
 	unsigned long max_data_hold_ns;
+	unsigned long min_data_setup_ns;
+	unsigned long min_setup_stop_ns;
+	unsigned long min_hold_buffer_ns;
 };
 
 static const struct i2c_spec_values standard_mode_spec = {
+	.min_hold_start_ns = 4000,
 	.min_low_ns = 4700,
 	.min_high_ns = 4000,
 	.min_setup_start_ns = 4700,
 	.max_data_hold_ns = 3450,
+	.min_data_setup_ns = 250,
+	.min_setup_stop_ns = 4000,
+	.min_hold_buffer_ns = 4700,
 };
 
 static const struct i2c_spec_values fast_mode_spec = {
+	.min_hold_start_ns = 600,
 	.min_low_ns = 1300,
 	.min_high_ns = 600,
 	.min_setup_start_ns = 600,
 	.max_data_hold_ns = 900,
+	.min_data_setup_ns = 100,
+	.min_setup_stop_ns = 600,
+	.min_hold_buffer_ns = 1300,
 };
 
 /**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
  * @div_high: Divider output for high
+ * @tuning: Used to adjust setup/hold data time,
+ * setup/hold start time and setup stop time for
+ * v1's calc_timings, the tuning should all be 0
+ * for old hardware anyone using v0's calc_timings.
  */
 struct rk3x_i2c_calced_timings {
 	unsigned long div_low;
 	unsigned long div_high;
+	unsigned int tuning;
 };
 
 enum rk3x_i2c_state {
@@ -123,9 +151,12 @@ enum rk3x_i2c_state {
 
 /**
  * @grf_offset: offset inside the grf regmap for setting the i2c type
+ * @calc_timings: Callback function for i2c timing information calculated
  */
 struct rk3x_i2c_soc_data {
 	int grf_offset;
+	int (*calc_timings)(unsigned long, struct i2c_timings *,
+			    struct rk3x_i2c_calced_timings *);
 };
 
 /**
@@ -134,7 +165,8 @@ struct rk3x_i2c_soc_data {
  * @dev: device for this controller
  * @soc_data: related soc data struct
  * @regs: virtual memory area
- * @clk: clock of i2c bus
+ * @clk: function clk for rk3399 or function & Bus clks for others
+ * @pclk: Bus clk for rk3399
  * @clk_rate_nb: i2c clk rate change notify
  * @t: I2C known timing information
  * @lock: spinlock for the i2c bus
@@ -156,6 +188,7 @@ struct rk3x_i2c {
 	/* Hardware resources */
 	void __iomem *regs;
 	struct clk *clk;
+	struct clk *pclk;
 	struct notifier_block clk_rate_nb;
 
 	/* Settings */
@@ -200,12 +233,12 @@ static inline void rk3x_i2c_clean_ipd(struct rk3x_i2c *i2c)
  */
 static void rk3x_i2c_start(struct rk3x_i2c *i2c)
 {
-	u32 val;
+	u32 val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
 
 	i2c_writel(i2c, REG_INT_START, REG_IEN);
 
 	/* enable adapter with correct mode, send START condition */
-	val = REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
+	val |= REG_CON_EN | REG_CON_MOD(i2c->mode) | REG_CON_START;
 
 	/* if we want to react to NACK, set ACTACK bit */
 	if (!(i2c->msg->flags & I2C_M_IGNORE_NAK))
@@ -246,7 +279,8 @@ static void rk3x_i2c_stop(struct rk3x_i2c *i2c, int error)
 		 * get the intended effect by resetting its internal state
 		 * and issuing an ordinary START.
 		 */
-		i2c_writel(i2c, 0, REG_CON);
+		ctrl = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+		i2c_writel(i2c, ctrl, REG_CON);
 
 		/* signal that we are finished with the current msg */
 		wake_up(&i2c->wait);
@@ -513,9 +547,9 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
  * a best-effort divider value is returned in divs. If the target rate is
  * too high, we silently use the highest possible rate.
  */
-static int rk3x_i2c_calc_divs(unsigned long clk_rate,
-			      struct i2c_timings *t,
-			      struct rk3x_i2c_calced_timings *t_calc)
+static int rk3x_i2c_v0_calc_timings(unsigned long clk_rate,
+				    struct i2c_timings *t,
+				    struct rk3x_i2c_calced_timings *t_calc)
 {
 	unsigned long min_low_ns, min_high_ns;
 	unsigned long max_low_ns, min_total_ns;
@@ -661,20 +695,191 @@ static int rk3x_i2c_calc_divs(unsigned long clk_rate,
 	return ret;
 }
 
+/**
+ * Calculate timing values for desired SCL frequency
+ *
+ * @clk_rate: I2C input clock rate
+ * @t: Known I2C timing information
+ * @t_calc: Caculated rk3x private timings that would be written into regs
+ *
+ * Returns: 0 on success, -EINVAL if the goal SCL rate is too slow. In that case
+ * a best-effort divider value is returned in divs. If the target rate is
+ * too high, we silently use the highest possible rate.
+ * The following formulas are v1's method to calculate timings.
+ *
+ * l = divl + 1;
+ * h = divh + 1;
+ * s = sda_update_config + 1;
+ * u = start_setup_config + 1;
+ * p = stop_setup_config + 1;
+ * T = Tclk_i2c;
+ *
+ * tHigh = 8 * h * T;
+ * tLow = 8 * l * T;
+ *
+ * tHD;sda = (l * s + 1) * T;
+ * tSU;sda = [(8 - s) * l + 1] * T;
+ * tI2C = 8 * (l + h) * T;
+ *
+ * tSU;sta = (8h * u + 1) * T;
+ * tHD;sta = [8h * (u + 1) - 1] * T;
+ * tSU;sto = (8h * p + 1) * T;
+ */
+static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
+				    struct i2c_timings *t,
+				    struct rk3x_i2c_calced_timings *t_calc)
+{
+	unsigned long min_low_ns, min_high_ns, min_total_ns;
+	unsigned long min_setup_start_ns, min_setup_data_ns;
+	unsigned long min_setup_stop_ns, max_hold_data_ns;
+
+	unsigned long clk_rate_khz, scl_rate_khz;
+
+	unsigned long min_low_div, min_high_div;
+
+	unsigned long min_div_for_hold, min_total_div;
+	unsigned long extra_div, extra_low_div;
+	unsigned long sda_update_cfg, stp_sta_cfg, stp_sto_cfg;
+
+	const struct i2c_spec_values *spec;
+	int ret = 0;
+
+	/* Support standard-mode and fast-mode */
+	if (WARN_ON(t->bus_freq_hz > 400000))
+		t->bus_freq_hz = 400000;
+
+	/* prevent scl_rate_khz from becoming 0 */
+	if (WARN_ON(t->bus_freq_hz < 1000))
+		t->bus_freq_hz = 1000;
+
+	/*
+	 * min_low_ns: The minimum number of ns we need to hold low to
+	 *	       meet I2C specification, should include fall time.
+	 * min_high_ns: The minimum number of ns we need to hold high to
+	 *	        meet I2C specification, should include rise time.
+	 */
+	spec = rk3x_i2c_get_spec(t->bus_freq_hz);
+
+	/* calculate min-divh and min-divl */
+	clk_rate_khz = DIV_ROUND_UP(clk_rate, 1000);
+	scl_rate_khz = t->bus_freq_hz / 1000;
+	min_total_div = DIV_ROUND_UP(clk_rate_khz, scl_rate_khz * 8);
+
+	min_high_ns = t->scl_rise_ns + spec->min_high_ns;
+	min_high_div = DIV_ROUND_UP(clk_rate_khz * min_high_ns, 8 * 1000000);
+
+	min_low_ns = t->scl_fall_ns + spec->min_low_ns;
+	min_low_div = DIV_ROUND_UP(clk_rate_khz * min_low_ns, 8 * 1000000);
+
+	/*
+	 * Final divh and divl must be greater than 0, otherwise the
+	 * hardware would not output the i2c clk.
+	 */
+	min_high_div = (min_high_div < 1) ? 2 : min_high_div;
+	min_low_div = (min_low_div < 1) ? 2 : min_low_div;
+
+	/* These are the min dividers needed for min hold times. */
+	min_div_for_hold = (min_low_div + min_high_div);
+	min_total_ns = min_low_ns + min_high_ns;
+
+	/*
+	 * This is the maximum divider so we don't go over the maximum.
+	 * We don't round up here (we round down) since this is a maximum.
+	 */
+	 if (min_div_for_hold >= min_total_div) {
+		/*
+		 * Time needed to meet hold requirements is important.
+		 * Just use that.
+		 */
+		t_calc->div_low = min_low_div;
+		t_calc->div_high = min_high_div;
+	} else {
+		/*
+		 * We've got to distribute some time among the low and high
+		 * so we don't run too fast.
+		 * We'll try to split things up by the scale of min_low_div and
+		 * min_high_div, biasing slightly towards having a higher div
+		 * for low (spend more time low).
+		 */
+		extra_div = min_total_div - min_div_for_hold;
+		extra_low_div = DIV_ROUND_UP(min_low_div * extra_div,
+					     min_div_for_hold);
+
+		t_calc->div_low = min_low_div + extra_low_div;
+		t_calc->div_high = min_high_div + (extra_div - extra_low_div);
+	}
+
+	/*
+	 * calculate sda data hold count by the rules, data_upd_st:3
+	 * is a appropriate value to reduce calculated times.
+	 */
+	for (sda_update_cfg = 3; sda_update_cfg > 0; sda_update_cfg--) {
+		max_hold_data_ns =  DIV_ROUND_UP((sda_update_cfg
+						 * (t_calc->div_low) + 1)
+						 * 1000000, clk_rate_khz);
+		min_setup_data_ns =  DIV_ROUND_UP(((8 - sda_update_cfg)
+						 * (t_calc->div_low) + 1)
+						 * 1000000, clk_rate_khz);
+		if ((max_hold_data_ns < spec->max_data_hold_ns) &&
+		    (min_setup_data_ns > spec->min_data_setup_ns))
+			break;
+	}
+
+	/* calculate setup start config */
+	min_setup_start_ns = t->scl_rise_ns + spec->min_setup_start_ns;
+	stp_sta_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_start_ns
+			   - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+	/* calculate setup stop config */
+	min_setup_stop_ns = t->scl_rise_ns + spec->min_setup_stop_ns;
+	stp_sto_cfg = DIV_ROUND_UP(clk_rate_khz * min_setup_stop_ns
+			   - 1000000, 8 * 1000000 * (t_calc->div_high));
+
+	t_calc->tuning = REG_CON_SDA_CFG(--sda_update_cfg) |
+			 REG_CON_STA_CFG(--stp_sta_cfg) |
+			 REG_CON_STO_CFG(--stp_sto_cfg);
+
+	t_calc->div_low--;
+	t_calc->div_high--;
+
+	/* Maximum divider supported by hw is 0xffff */
+	if (t_calc->div_low > 0xffff) {
+		t_calc->div_low = 0xffff;
+		ret = -EINVAL;
+	}
+
+	if (t_calc->div_high > 0xffff) {
+		t_calc->div_high = 0xffff;
+		ret = -EINVAL;
+	}
+
+	return ret;
+}
+
 static void rk3x_i2c_adapt_div(struct rk3x_i2c *i2c, unsigned long clk_rate)
 {
 	struct i2c_timings *t = &i2c->t;
 	struct rk3x_i2c_calced_timings calc;
 	u64 t_low_ns, t_high_ns;
+	unsigned long flags;
+	u32 val;
 	int ret;
 
-	ret = rk3x_i2c_calc_divs(clk_rate, t, &calc);
+	ret = i2c->soc_data->calc_timings(clk_rate, t, &calc);
 	WARN_ONCE(ret != 0, "Could not reach SCL freq %u", t->bus_freq_hz);
 
-	clk_enable(i2c->clk);
+	clk_enable(i2c->pclk);
+
+	spin_lock_irqsave(&i2c->lock, flags);
+	val = i2c_readl(i2c, REG_CON);
+	val &= ~REG_CON_TUNING_MASK;
+	val |= calc.tuning;
+	i2c_writel(i2c, val, REG_CON);
 	i2c_writel(i2c, (calc.div_high << 16) | (calc.div_low & 0xffff),
 		   REG_CLKDIV);
-	clk_disable(i2c->clk);
+	spin_unlock_irqrestore(&i2c->lock, flags);
+
+	clk_disable(i2c->pclk);
 
 	t_low_ns = div_u64(((u64)calc.div_low + 1) * 8 * 1000000000, clk_rate);
 	t_high_ns = div_u64(((u64)calc.div_high + 1) * 8 * 1000000000,
@@ -712,7 +917,13 @@ static int rk3x_i2c_clk_notifier_cb(struct notifier_block *nb, unsigned long
 
 	switch (event) {
 	case PRE_RATE_CHANGE:
-		if (rk3x_i2c_calc_divs(ndata->new_rate, &i2c->t, &calc) != 0)
+		/*
+		 * Try the calculation (but don't store the result) ahead of
+		 * time to see if we need to block the clock change.  Timings
+		 * shouldn't actually take effect until rk3x_i2c_adapt_div().
+		 */
+		if (i2c->soc_data->calc_timings(ndata->new_rate, &i2c->t,
+						&calc) != 0)
 			return NOTIFY_STOP;
 
 		/* scale up */
@@ -822,12 +1033,14 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 {
 	struct rk3x_i2c *i2c = (struct rk3x_i2c *)adap->algo_data;
 	unsigned long timeout, flags;
+	u32 val;
 	int ret = 0;
 	int i;
 
 	spin_lock_irqsave(&i2c->lock, flags);
 
 	clk_enable(i2c->clk);
+	clk_enable(i2c->pclk);
 
 	i2c->is_last_msg = false;
 
@@ -861,7 +1074,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 
 			/* Force a STOP condition without interrupt */
 			i2c_writel(i2c, 0, REG_IEN);
-			i2c_writel(i2c, REG_CON_EN | REG_CON_STOP, REG_CON);
+			val = i2c_readl(i2c, REG_CON) & REG_CON_TUNING_MASK;
+			val |= REG_CON_EN | REG_CON_STOP;
+			i2c_writel(i2c, val, REG_CON);
 
 			i2c->state = STATE_IDLE;
 
@@ -875,7 +1090,9 @@ static int rk3x_i2c_xfer(struct i2c_adapter *adap,
 		}
 	}
 
+	clk_disable(i2c->pclk);
 	clk_disable(i2c->clk);
+
 	spin_unlock_irqrestore(&i2c->lock, flags);
 
 	return ret < 0 ? ret : num;
@@ -893,18 +1110,27 @@ static const struct i2c_algorithm rk3x_i2c_algorithm = {
 
 static const struct rk3x_i2c_soc_data rk3066_soc_data = {
 	.grf_offset = 0x154,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3188_soc_data = {
 	.grf_offset = 0x0a4,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3228_soc_data = {
 	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
 };
 
 static const struct rk3x_i2c_soc_data rk3288_soc_data = {
 	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v0_calc_timings,
+};
+
+static const struct rk3x_i2c_soc_data rk3399_soc_data = {
+	.grf_offset = -1,
+	.calc_timings = rk3x_i2c_v1_calc_timings,
 };
 
 static const struct of_device_id rk3x_i2c_match[] = {
@@ -924,6 +1150,10 @@ static const struct of_device_id rk3x_i2c_match[] = {
 		.compatible = "rockchip,rk3288-i2c",
 		.data = (void *)&rk3288_soc_data
 	},
+	{
+		.compatible = "rockchip,rk3399-i2c",
+		.data = (void *)&rk3399_soc_data
+	},
 	{},
 };
 MODULE_DEVICE_TABLE(of, rk3x_i2c_match);
@@ -963,12 +1193,6 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 	spin_lock_init(&i2c->lock);
 	init_waitqueue_head(&i2c->wait);
 
-	i2c->clk = devm_clk_get(&pdev->dev, NULL);
-	if (IS_ERR(i2c->clk)) {
-		dev_err(&pdev->dev, "cannot get clock\n");
-		return PTR_ERR(i2c->clk);
-	}
-
 	mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	i2c->regs = devm_ioremap_resource(&pdev->dev, mem);
 	if (IS_ERR(i2c->regs))
@@ -1022,17 +1246,44 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 
 	platform_set_drvdata(pdev, i2c);
 
+	if (i2c->soc_data->calc_timings == rk3x_i2c_v0_calc_timings) {
+		/* Only one clock to use for bus clock and peripheral clock */
+		i2c->clk = devm_clk_get(&pdev->dev, NULL);
+		i2c->pclk = i2c->clk;
+	} else {
+		i2c->clk = devm_clk_get(&pdev->dev, "i2c");
+		i2c->pclk = devm_clk_get(&pdev->dev, "pclk");
+	}
+
+	if (IS_ERR(i2c->clk)) {
+		ret = PTR_ERR(i2c->clk);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Can't get bus clk: %d\n", ret);
+		return ret;
+	}
+	if (IS_ERR(i2c->pclk)) {
+		ret = PTR_ERR(i2c->pclk);
+		if (ret != -EPROBE_DEFER)
+			dev_err(&pdev->dev, "Can't get periph clk: %d\n", ret);
+		return ret;
+	}
+
 	ret = clk_prepare(i2c->clk);
 	if (ret < 0) {
-		dev_err(&pdev->dev, "Could not prepare clock\n");
+		dev_err(&pdev->dev, "Can't prepare bus clk: %d\n", ret);
 		return ret;
 	}
+	ret = clk_prepare(i2c->pclk);
+	if (ret < 0) {
+		dev_err(&pdev->dev, "Can't prepare periph clock: %d\n", ret);
+		goto err_clk;
+	}
 
 	i2c->clk_rate_nb.notifier_call = rk3x_i2c_clk_notifier_cb;
 	ret = clk_notifier_register(i2c->clk, &i2c->clk_rate_nb);
 	if (ret != 0) {
 		dev_err(&pdev->dev, "Unable to register clock notifier\n");
-		goto err_clk;
+		goto err_pclk;
 	}
 
 	clk_rate = clk_get_rate(i2c->clk);
@@ -1050,6 +1301,8 @@ static int rk3x_i2c_probe(struct platform_device *pdev)
 
 err_clk_notifier:
 	clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+err_pclk:
+	clk_unprepare(i2c->pclk);
 err_clk:
 	clk_unprepare(i2c->clk);
 	return ret;
@@ -1062,6 +1315,7 @@ static int rk3x_i2c_remove(struct platform_device *pdev)
 	i2c_del_adapter(&i2c->adap);
 
 	clk_notifier_unregister(i2c->clk, &i2c->clk_rate_nb);
+	clk_unprepare(i2c->pclk);
 	clk_unprepare(i2c->clk);
 
 	return 0;
-- 
1.9.1




From david.wu at rock-chips.com  Mon May 16 07:06:29 2016
From: david.wu at rock-chips.com (David Wu)
Date: Mon, 16 May 2016 22:06:29 +0800
Subject: [PATCH v10 8/8] i2c: rk3x: support fast-mode plus for rk3399
In-Reply-To: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
References: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <1463407589-41520-1-git-send-email-david.wu@rock-chips.com>

Implement fast mode plus that allows bus speeds of up to 1MHz.

Signed-off-by: David Wu <david.wu at rock-chips.com>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
Tested-by: Caesar Wang <wxt at rock-chips.com>
Reviewed-by: Heiko Stuebner <heiko at sntech.de>
Tested-by: Heiko Stuebner <heiko at sntech.de>
---
Change in v10:
- none

Change in v9:
- add commit message

Change in v8:
- none

 drivers/i2c/busses/i2c-rk3x.c | 21 +++++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/drivers/i2c/busses/i2c-rk3x.c b/drivers/i2c/busses/i2c-rk3x.c
index a96b516..2938616 100644
--- a/drivers/i2c/busses/i2c-rk3x.c
+++ b/drivers/i2c/busses/i2c-rk3x.c
@@ -126,6 +126,17 @@ static const struct i2c_spec_values fast_mode_spec = {
 	.min_hold_buffer_ns = 1300,
 };
 
+static const struct i2c_spec_values fast_mode_plus_spec = {
+	.min_hold_start_ns = 260,
+	.min_low_ns = 500,
+	.min_high_ns = 260,
+	.min_setup_start_ns = 260,
+	.max_data_hold_ns = 400,
+	.min_data_setup_ns = 50,
+	.min_setup_stop_ns = 260,
+	.min_hold_buffer_ns = 500,
+};
+
 /**
  * struct rk3x_i2c_calced_timings:
  * @div_low: Divider output for low
@@ -532,8 +543,10 @@ static const struct i2c_spec_values *rk3x_i2c_get_spec(unsigned int speed)
 {
 	if (speed <= 100000)
 		return &standard_mode_spec;
-	else
+	else if (speed <= 400000)
 		return &fast_mode_spec;
+	else
+		return &fast_mode_plus_spec;
 }
 
 /**
@@ -744,9 +757,9 @@ static int rk3x_i2c_v1_calc_timings(unsigned long clk_rate,
 	const struct i2c_spec_values *spec;
 	int ret = 0;
 
-	/* Support standard-mode and fast-mode */
-	if (WARN_ON(t->bus_freq_hz > 400000))
-		t->bus_freq_hz = 400000;
+	/* Support standard-mode, fast-mode and fast-mode plus */
+	if (WARN_ON(t->bus_freq_hz > 1000000))
+		t->bus_freq_hz = 1000000;
 
 	/* prevent scl_rate_khz from becoming 0 */
 	if (WARN_ON(t->bus_freq_hz < 1000))
-- 
1.9.1




From dianders at chromium.org  Mon May 16 08:12:57 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 16 May 2016 08:12:57 -0700
Subject: [PATCH 3/4] phy: rockchip-emmc: configure default output tap delay
In-Reply-To: <52567d92-d1d3-f089-65c2-a30f3a00386b@rock-chips.com>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
 <1463092986-61777-3-git-send-email-briannorris@chromium.org>
 <CAD=FV=WupNv+z86BgmR1n8bj+b6GKA5Ew7U9hgoAxV9dxF7gjQ@mail.gmail.com>
 <52567d92-d1d3-f089-65c2-a30f3a00386b@rock-chips.com>
Message-ID: <CAD=FV=Xq3=B0NC7of-h_q8vCUDGz=33MU4vjY6EyQxQS+CC8=Q@mail.gmail.com>

Hi,

On Sun, May 15, 2016 at 9:15 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> Hi Doug,
>
>
> On 2016/5/14 6:25, Doug Anderson wrote:
>>
>> Hi,
>>
>> On Thu, May 12, 2016 at 3:43 PM, Brian Norris <briannorris at chromium.org>
>> wrote:
>>>
>>> The output tap delay controls helps maintain the hold requirements for
>>> eMMC. The exact value is dependent on the SoC and other factors, though
>>> it isn't really an exact science. But the default of 0 is not very good,
>>> as it doesn't give the eMMC much hold time, so let's bump up to 4
>>> (approx 90 degree phase?). If we need to configure this any further
>>> (e.g., based on board or speed factors), we may need to consider a
>>> device tree representation.
>>
>>
>> As I understand it, this solves much the same problem as my patch in
>> <https://patchwork.kernel.org/patch/9085581/>, but for the eMMC port
>> on rk3399 (which doesn't use dw_mmc).  As argued in that patch and
>> also in the discussion from
>> <https://patchwork.kernel.org/patch/9030621/>, if we eventually end up
>> needing to put something in the device tree we need to be really
>> careful.  Specifically to get the exact right value here I think you
>> need to consider the input clock, speed mode, and any SoC-specific
>> delays differences between the clock and the data lines.  That would
>> imply that, if anything, the device tree data would only contain
>> information about the SoC-specific delay differences and all other
>> work to set this value would involve coordination between the PHY and
>> the SDHCI controller.
>>
>>
>> However, as also discussed previously, we don't appear to need to be
>> very exact about the value here.  It seems like setting this to 4 (~90
>> degrees?) is a much better starting point than leaving it at the
>> default of 0.
>
>
> The value, 4, is based on real silicon test observed from the
> oscilloscope, and of course it meets the requirement of speed modes.
> For arasan't phy, its phase is very accurate, so the real timing of
> the value you set almost won't vary too much for different Socs.
>
> So explicitly assigning 4 here looks sane currently except for crazy
> PCB layout...

Great to hear.  So we can probably just use your email as the basis of
the commit message?  How about this for the commit text then:

The output tap delay controls helps maintain the hold requirements for
eMMC.  The value, 4, is based on real silicon test observed from the
oscilloscope, and of course it meets the requirement of speed modes.
For arasan't phy, its phase is very accurate, so the real timing of
the value you set won't vary too much for different SoCs.

If / when we find an instance of a crazy PCB layout that needs a value
different than 4, we will figure out how to best specify that,
possibly using the device tree in some way.

-Doug


From dianders at chromium.org  Mon May 16 08:49:01 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 16 May 2016 08:49:01 -0700
Subject: [PATCH 2/2] clk: rockchip: fix incorrect parent for rk3399's {c,
 g}pll_aclk_perihp_src
In-Reply-To: <57369D2E.3030002@rock-chips.com>
References: <1463164937-91089-1-git-send-email-briannorris@chromium.org>
 <1463164937-91089-2-git-send-email-briannorris@chromium.org>
 <CAD=FV=XstYhqpStSGw5PObWvpsvd3Nwp_hfEE-56bpFoVUyu+g@mail.gmail.com>
 <57369D2E.3030002@rock-chips.com>
Message-ID: <CAD=FV=Wda=kXYf4MnjXsW6g8sPAAEv7JO1ZoGXOnJW=aL0yv-w@mail.gmail.com>

Hi,

On Fri, May 13, 2016 at 8:36 PM, Xing Zheng <zhengxing at rock-chips.com> wrote:
> Hi Doug,
>
>
> On 2016?05?14? 04:10, Doug Anderson wrote:
>>
>> Hi,
>>
>> On Fri, May 13, 2016 at 11:42 AM, Brian Norris <briannorris at chromium.org>
>> wrote:
>>>
>>> From: Xing Zheng <zhengxing at rock-chips.com>
>>>
>>> There was a typo, swapping 'c' <--> 'g'.
>>>
>>> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
>>> Signed-off-by: Brian Norris <briannorris at chromium.org>
>>> ---
>>>   drivers/clk/rockchip/clk-rk3399.c | 4 ++--
>>>   1 file changed, 2 insertions(+), 2 deletions(-)
>>>
>>> diff --git a/drivers/clk/rockchip/clk-rk3399.c
>>> b/drivers/clk/rockchip/clk-rk3399.c
>>> index 145756c4f3c8..9f86bfef70f7 100644
>>> --- a/drivers/clk/rockchip/clk-rk3399.c
>>> +++ b/drivers/clk/rockchip/clk-rk3399.c
>>> @@ -832,9 +832,9 @@ static struct rockchip_clk_branch
>>> rk3399_clk_branches[] __initdata = {
>>>                          RK3399_CLKGATE_CON(13), 1, GFLAGS),
>>>
>>>          /* perihp */
>>> -       GATE(0, "cpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED,
>>> +       GATE(0, "cpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED,
>>>                          RK3399_CLKGATE_CON(5), 0, GFLAGS),
>>> -       GATE(0, "gpll_aclk_perihp_src", "cpll", CLK_IGNORE_UNUSED,
>>> +       GATE(0, "gpll_aclk_perihp_src", "gpll", CLK_IGNORE_UNUSED,
>>>                          RK3399_CLKGATE_CON(5), 1, GFLAGS),
>>>          COMPOSITE(ACLK_PERIHP, "aclk_perihp", mux_aclk_perihp_p,
>>> CLK_IGNORE_UNUSED,
>>>                          RK3399_CLKSEL_CON(14), 7, 1, MFLAGS, 0, 5,
>>> DFLAGS,
>>
>> Definitely there was a bug since this table itself was inconsistent.
>> ...and I _think_ this fix is correct, but I'll note that the TRM has
>> more inconsistency here.
>>
>> In the big clock table 'CRU Clock Architecture Diagram', I see:
>>    CLK 4 is CPLL
>>    CLK 5 is GPLL
>>    CLK 125 is aclk_perihp_cpll_src and has 4 (CPLL) as source, with
>> g5[0] as the bit
>>    CLK 126 is aclk_perihp_gpll_src and has 5 (GPLL) as source, with
>> g5[1] as the bit
>>
>> In the definition of CRU_CLKGATE_CON5:
>>    bit 0 shows aclk_perihp_gpll_src_en
>>    bit 1 shows aclk_perihp_cpll_src_en
>>
>>
>> Thus the table shows CPLL as gate5[0] and GPLL as gate5[1].  The
>> register definition shows the opposite.  I'll tend to believe the
>> table over the register definition, but I figured I'd bring it up
>> anyway.
>>
>>
>> Xing Zheng: can you confirm that the table is correct and ask
>> documentation folks to fix the register definition for
>> CRU_CLKGATE_CON5?
>
> Yes, previously, our IC & DOC partner confirmed that the definition of
> CRU_CLKGATE_CON5 should be:
>   bit 0 shows aclk_perihp_cpll_src_en
>   bit 1 shows aclk_perihp_gpll_src_en
>
> Sorry to the incorrect register definition, we will fix them and review the
> TRM again.

Great!

Since we now have extra confirmation that Brian's patch is indeed correct:

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From robh at kernel.org  Mon May 16 09:45:38 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 16 May 2016 11:45:38 -0500
Subject: [PATCH v10 6/8] dt-bindings: i2c: rk3x: add support for rk3399
In-Reply-To: <1463407452-41418-1-git-send-email-david.wu@rock-chips.com>
References: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
 <1463407452-41418-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <20160516164538.GA27178@rob-hp-laptop>

On Mon, May 16, 2016 at 10:04:12PM +0800, David Wu wrote:
> The bus clock and function clock are separated at rk3399,
> and others use one clock as the bus clock and function clock.
> 
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>
> Reviewed-by: Heiko Stuebner <heiko at sntech.de>
> Tested-by: Heiko Stuebner <heiko at sntech.de>
> ---
> Change in v10:
> - none
> 
> Change in v9:
> - remove unnecessary "REQUIRED".
> 
> Change in v8:
> - remove error description.
> 
>  Documentation/devicetree/bindings/i2c/i2c-rk3x.txt | 16 +++++++++++++---
>  1 file changed, 13 insertions(+), 3 deletions(-)

Acked-by: Rob Herring <robh at kernel.org>


From dianders at chromium.org  Mon May 16 10:22:41 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 16 May 2016 10:22:41 -0700
Subject: [PATCH v10 7/8] i2c: rk3x: add i2c support for rk3399 soc
In-Reply-To: <1463407503-41466-1-git-send-email-david.wu@rock-chips.com>
References: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
 <1463407503-41466-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=UZ+HF-21UJv1xS4a-yssYGC5Y71ngn2=wGSOkceiV+yQ@mail.gmail.com>

David,

On Mon, May 16, 2016 at 7:05 AM, David Wu <david.wu at rock-chips.com> wrote:
> - new method to caculate i2c timings for rk3399:
>   There was an timing issue about "repeated start" time at the I2C
>   controller of version0, controller appears to drop SDA at .875x (7/8)
>   programmed clk high. On version 1 of the controller, the rule(.875x)
>   isn't enough to meet tSU;STA
>   requirements on 100k's Standard-mode. To resolve this issue,
>   sda_update_config, start_setup_config and stop_setup_config for I2C
>   timing information are added, new rules are designed to calculate
>   the timing information at new v1.
> - pclk and function clk are separated at rk3399
>
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Tested-by: Caesar Wang <wxt at rock-chips.com>
> Tested-by: Heiko Stuebner <heiko at sntech.de>
> ---
> Change in v10:
> - fix the clean of con register in rk3x_i2c_stop()
>
> Change in v9:
> - add spin lock for tuning updated in rk3x_i2c_adapt_div() (Doug)
>
> Changes in v8:
> - update tuning in RKI2C_CON register by doing a read-modify-write (Doug)
> - new method to use pclk and clk (Doug)
>
> Changes in v7:
> - transform into a 9 series patches (Doug)
> - drop highspeed with mastercode, and support fast-mode plus (Doug)
>
>  drivers/i2c/busses/i2c-rk3x.c | 294 +++++++++++++++++++++++++++++++++++++++---
>  1 file changed, 274 insertions(+), 20 deletions(-)

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Mon May 16 13:09:31 2016
From: dianders at chromium.org (Douglas Anderson)
Date: Mon, 16 May 2016 13:09:31 -0700
Subject: [PATCH] arm64: dts: rockchip: add i2c nodes for rk3399
Message-ID: <1463429371-10950-1-git-send-email-dianders@chromium.org>

From: David Wu <david.wu at rock-chips.com>

We've got 9 (count em!) i2c controllers on rk3399, some of which are in
the PMU power domain and some of which are normal peripherals.  Add them
all to the main rk3399 dtsi file so future patches can turn them on in
the board dts files.

Note: by default we try to set the i2c clock rate to 200 MHz so that we
can achieve good i2c functional clock rates.  200 MHz gives us the
ability to make very close to 100 kHz / 400 kHz / 1 MHz rates.  If
boards want to tune clock rates further they can always override.
Possibly boards could want to tune this if:
- they wanted to save an infinitesimal amount of power and they knew
  their i2c bus was slow anyway.  Since we gate the functional clock
  when the i2c bus is not active, power savings would only be while i2c
  transfers were happening and probably won't be very big anyway.
- they wanted to eek out a bit more speed by carefully tuning the source
  clock to make divisions work out perfectly, accounting for the rise /
  fall time measured on an actual board.

Note also that we still request 200 MHz for the PMU i2c busses even
though we expect that we won't make that exactly (currently PPLL is 676
MHz which gives us 169 MHz).

Signed-off-by: David Wu <david.wu at rock-chips.com>
Signed-off-by: Jianqun Xu <jay.xu at rock-chips.com>
[dianders: wrote desc; put in assigned-clocks; reordered nodes]
Signed-off-by: Douglas Anderson <dianders at chromium.org>
---
Note: this patch is based upon David Wu's patch series to add rk3399
support to i2c-rk3x.c and shouldn't land until at least device tree
bindings land.

 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 144 +++++++++++++++++++++++++++++++
 1 file changed, 144 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a143b0..753a91728b4c 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -54,6 +54,15 @@
 	#size-cells = <2>;
 
 	aliases {
+		i2c0 = &i2c0;
+		i2c1 = &i2c1;
+		i2c2 = &i2c2;
+		i2c3 = &i2c3;
+		i2c4 = &i2c4;
+		i2c5 = &i2c5;
+		i2c6 = &i2c6;
+		i2c7 = &i2c7;
+		i2c8 = &i2c8;
 		serial0 = &uart0;
 		serial1 = &uart1;
 		serial2 = &uart2;
@@ -272,6 +281,96 @@
 		};
 	};
 
+	i2c1: i2c at ff110000 {
+		compatible = "rockchip,rk3399-i2c";
+		reg = <0x0 0xff110000 0x0 0x1000>;
+		assigned-clocks = <&cru SCLK_I2C1>;
+		assigned-clock-rates = <200000000>;
+		clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>;
+		clock-names = "i2c", "pclk";
+		interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c1_xfer>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c2: i2c at ff120000 {
+		compatible = "rockchip,rk3399-i2c";
+		reg = <0x0 0xff120000 0x0 0x1000>;
+		assigned-clocks = <&cru SCLK_I2C2>;
+		assigned-clock-rates = <200000000>;
+		clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>;
+		clock-names = "i2c", "pclk";
+		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c2_xfer>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c3: i2c at ff130000 {
+		compatible = "rockchip,rk3399-i2c";
+		reg = <0x0 0xff130000 0x0 0x1000>;
+		assigned-clocks = <&cru SCLK_I2C3>;
+		assigned-clock-rates = <200000000>;
+		clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;
+		clock-names = "i2c", "pclk";
+		interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c3_xfer>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c5: i2c at ff140000 {
+		compatible = "rockchip,rk3399-i2c";
+		reg = <0x0 0xff140000 0x0 0x1000>;
+		assigned-clocks = <&cru SCLK_I2C5>;
+		assigned-clock-rates = <200000000>;
+		clocks = <&cru SCLK_I2C5>, <&cru PCLK_I2C5>;
+		clock-names = "i2c", "pclk";
+		interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c5_xfer>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c6: i2c at ff150000 {
+		compatible = "rockchip,rk3399-i2c";
+		reg = <0x0 0xff150000 0x0 0x1000>;
+		assigned-clocks = <&cru SCLK_I2C6>;
+		assigned-clock-rates = <200000000>;
+		clocks = <&cru SCLK_I2C6>, <&cru PCLK_I2C6>;
+		clock-names = "i2c", "pclk";
+		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c6_xfer>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c7: i2c at ff160000 {
+		compatible = "rockchip,rk3399-i2c";
+		reg = <0x0 0xff160000 0x0 0x1000>;
+		assigned-clocks = <&cru SCLK_I2C7>;
+		assigned-clock-rates = <200000000>;
+		clocks = <&cru SCLK_I2C7>, <&cru PCLK_I2C7>;
+		clock-names = "i2c", "pclk";
+		interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c7_xfer>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
 	uart0: serial at ff180000 {
 		compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
 		reg = <0x0 0xff180000 0x0 0x100>;
@@ -420,6 +519,51 @@
 		status = "disabled";
 	};
 
+	i2c0: i2c at ff3c0000 {
+		compatible = "rockchip,rk3399-i2c";
+		reg = <0x0 0xff3c0000 0x0 0x1000>;
+		assigned-clocks = <&pmucru SCLK_I2C0_PMU>;
+		assigned-clock-rates = <200000000>;
+		clocks = <&pmucru SCLK_I2C0_PMU>, <&pmucru PCLK_I2C0_PMU>;
+		clock-names = "i2c", "pclk";
+		interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c0_xfer>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c4: i2c at ff3d0000 {
+		compatible = "rockchip,rk3399-i2c";
+		reg = <0x0 0xff3d0000 0x0 0x1000>;
+		assigned-clocks = <&pmucru SCLK_I2C4_PMU>;
+		assigned-clock-rates = <200000000>;
+		clocks = <&pmucru SCLK_I2C4_PMU>, <&pmucru PCLK_I2C4_PMU>;
+		clock-names = "i2c", "pclk";
+		interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c4_xfer>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
+	i2c8: i2c at ff3e0000 {
+		compatible = "rockchip,rk3399-i2c";
+		reg = <0x0 0xff3e0000 0x0 0x1000>;
+		assigned-clocks = <&pmucru SCLK_I2C8_PMU>;
+		assigned-clock-rates = <200000000>;
+		clocks = <&pmucru SCLK_I2C8_PMU>, <&pmucru PCLK_I2C8_PMU>;
+		clock-names = "i2c", "pclk";
+		interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+		pinctrl-names = "default";
+		pinctrl-0 = <&i2c8_xfer>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+	};
+
 	pwm0: pwm at ff420000 {
 		compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
 		reg = <0x0 0xff420000 0x0 0x10>;
-- 
2.8.0.rc3.226.g39d4020



From dianders at chromium.org  Mon May 16 13:17:38 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 16 May 2016 13:17:38 -0700
Subject: [PATCH v10 0/8] add i2c driver supported for rk3399
In-Reply-To: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
References: <1463407063-41218-1-git-send-email-david.wu@rock-chips.com>
Message-ID: <CAD=FV=VqEpmODcnKOGb5P=Fu84c5pBOJXD9pfFMRc2aERfWmRg@mail.gmail.com>

Hi,

On Mon, May 16, 2016 at 6:57 AM, David Wu <david.wu at rock-chips.com> wrote:
> There are three points differert from others:
>  - new method to caculate i2c timings for rk3399
>  - pclk and function clk are separated at rk3399
>  - add fast-plus mode supported for rk3399
>
> David Wu (8):
>   i2c: rk3x: add documentation to fields in "struct rk3x_i2c"
>   i2c: rk3x: use struct "rk3x_i2c_calced_timings"
>   i2c: rk3x: Remove redundant rk3x_i2c_clean_ipd()
>   i2c: rk3x: Change SoC data to not use array
>   i2c: rk3x: Move spec timing data to "static const" structs
>   dt-bindings: i2c: rk3x: add support for rk3399
>   i2c: rk3x: add i2c support for rk3399 soc
>   i2c: rk3x: support fast-mode plus for rk3399
>
>  Documentation/devicetree/bindings/i2c/i2c-rk3x.txt |  16 +-
>  drivers/i2c/busses/i2c-rk3x.c                      | 498 +++++++++++++++++----
>  2 files changed, 434 insertions(+), 80 deletions(-)

I haven't put these on the scope or anything, but I have:

* Tested that my i2c busses on rk3288-veyron still seem to work OK
after these patches.

* Tested that my i2c busses on an rk3399 board seem to work after
these patches (plus device tree changes).

Thus, for the series:

Tested-by: Douglas Anderson <dianders at chromium.org>

...possibly could leave off the Tested-by tag for the last in the
series since I have no Fast Mode Plus devices to test against.  ;)

-Doug


From eballetbo at gmail.com  Tue May 17 01:14:55 2016
From: eballetbo at gmail.com (Enric Balletbo Serra)
Date: Tue, 17 May 2016 10:14:55 +0200
Subject: [alsa-devel] [PATCH v2 4/5] ARM: dts: rockchip: Add shared file
 for audio related nodes for veyron boards
In-Reply-To: <1769207.YFf2RsNhBy@phil>
References: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
 <1462790795-25345-5-git-send-email-enric.balletbo@collabora.com>
 <1769207.YFf2RsNhBy@phil>
Message-ID: <CAFqH_51XmijOmfY2K1Yxcq1=x8T6m5nC0C5_2Qz-7FVR02HrMA@mail.gmail.com>

Hi Heiko,

2016-05-16 0:06 GMT+02:00 Heiko Stuebner <heiko at sntech.de>:
> Am Montag, 9. Mai 2016, 12:46:34 schrieb Enric Balletbo i Serra:
>> Set i2s block to "okay", add sound node for max98090 with gpios for
>> HP and Mic detect and pinctrl, and add a max98090 device and ts3a227e to
>> the correct i2c bus.
>>
>> Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
>
> I only got a "applied" reply from Marks scripts for patch 3/5, so only today
> saw that all 3 actually got applied.
>
> Anyway, I've applied this to my dts32-branch for 4.8 now [0] with some
> modifications regarding
> - the commit subject+message
> - ordering
> - io_domains access (via the phandle now)
> - regulator suspend property
> so maybe take a look and holler if you see a mistake.
>

The changes looks good to me, thanks.

> I was able to get audio over the headphones (so definitly an improvement),
> but so far not over the built-in speakers. Did you need to do something
> special in the configuration for this?
>

I added an UCM file [1] to my setup to test this and tested as follows
(you can also use alsamixer but as you know this is not safe though ;)
)

# enable the speaker at bootup:
alsaucm -c ROCKCHIP-I2S set _verb HiFi
# set speaker to half loudness:
amixer set Speaker 50%
# play something
aplay music.wav
# enable headphones (disable speaker):
alsaucm -c ROCKCHIP-I2S set _verb HiFi set _enadev Headphone
# set headphones to half loudness:
amixer set Headphone 50%
# play something
aplay music.wav
# disable headphones (enable speaker):
alsaucm -c ROCKCHIP-I2S set _verb HiFi set _disdev Headphone


[1] http://git.alsa-project.org/?p=alsa-lib.git;a=commit;h=a192f52fc63a86e1fbb9a09adb0bc2a6bbc8dab1

>
> Heiko
>
> [0] https://git.kernel.org/cgit/linux/kernel/git/mmind/linux-rockchip.git/commit/?h=volatile-v4.8-armsoc/dts32&id=1452aee5a7acc03518ef5215dd3dbac4444efe52
>
>> ---
>> Changes since v1:
>>  - None
>>
>>  arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi | 102
>> ++++++++++++++++++++++ 1 file changed, 102 insertions(+)
>>  create mode 100644 arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
>>
>> diff --git a/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
>> b/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi new file mode 100644
>> index 0000000..f045e1a
>> --- /dev/null
>> +++ b/arch/arm/boot/dts/rk3288-veyron-analog-audio.dtsi
>> @@ -0,0 +1,102 @@
>> +/*
>> + * Google Veyron (and derivatives) fragment for the  max98090 audio
>> + * codec and analog headphone jack.
>> + *
>> + * Copyright 2016 Google, Inc
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License version 2 as
>> + * published by the Free Software Foundation.
>> + */
>> +
>> +/ {
>> +
>> +     sound {
>> +             compatible = "rockchip,rockchip-audio-max98090";
>> +             rockchip,model = "ROCKCHIP-I2S";
>> +             rockchip,i2s-controller = <&i2s>;
>> +             rockchip,audio-codec = <&max98090>;
>> +             rockchip,hp-det-gpios = <&gpio6 5 GPIO_ACTIVE_HIGH>;
>> +             rockchip,mic-det-gpios = <&gpio6 11 GPIO_ACTIVE_LOW>;
>> +             rockchip,headset-codec = <&headsetcodec>;
>> +             pinctrl-names = "default";
>> +             pinctrl-0 = <&mic_det>, <&hp_det>;
>> +     };
>> +
>> +     io-domains {
>> +             audio-supply = <&vcc18_codec>;
>> +     };
>> +};
>> +
>> +&rk808 {
>> +     vcc10-supply = <&vcc33_sys>;
>> +
>> +     regulators {
>> +             vcc18_codec: LDO_REG6 {
>> +                     regulator-always-on;
>> +                     regulator-boot-on;
>> +                     regulator-min-microvolt = <1800000>;
>> +                     regulator-max-microvolt = <1800000>;
>> +                     regulator-name = "vcc18_codec";
>> +                     regulator-suspend-mem-disabled;
>> +             };
>> +     };
>> +};
>> +
>> +&i2c2 {
>> +     max98090: max98090 at 10 {
>> +             compatible = "maxim,max98090";
>> +             reg = <0x10>;
>> +             clock-names = "mclk";
>> +             clocks = <&cru SCLK_I2S0_OUT>;
>> +             interrupt-parent = <&gpio6>;
>> +             interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
>> +             pinctrl-names = "default";
>> +             pinctrl-0 = <&int_codec>;
>> +     };
>> +};
>> +
>> +&i2c4 {
>> +     headsetcodec: ts3a227e at 3b {
>> +             compatible = "ti,ts3a227e";
>> +             reg = <0x3b>;
>> +             interrupt-parent = <&gpio0>;
>> +             interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
>> +             pinctrl-names = "default";
>> +             pinctrl-0 = <&ts3a227e_int_l>;
>> +             ti,micbias = <7>;               /* MICBIAS = 2.8V */
>> +     };
>> +};
>> +
>> +&i2s {
>> +     status = "okay";
>> +     clock-names = "i2s_hclk", "i2s_clk";
>> +     clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
>> +};
>> +
>> +&pinctrl {
>> +     codec {
>> +             hp_det: hp-det {
>> +                     rockchip,pins = <6 5 RK_FUNC_GPIO &pcfg_pull_up>;
>> +             };
>> +
>> +             /*
>> +              * HACK: We're going to _pull down_ this _active low_ interrupt
>> +              * so that it never fires.  We don't need this interrupt because
>> +              * we've got a ts3a227e chip but the driver requires it.
>> +              */
>> +             int_codec: int-codec {
>> +                     rockchip,pins = <6 7 RK_FUNC_GPIO &pcfg_pull_down>;
>> +             };
>> +
>> +             mic_det: mic-det {
>> +                     rockchip,pins = <6 11 RK_FUNC_GPIO &pcfg_pull_up>;
>> +             };
>> +     };
>> +
>> +     headset {
>> +             ts3a227e_int_l: ts3a227e-int-l {
>> +                     rockchip,pins = <0 3 RK_FUNC_GPIO &pcfg_pull_up>;
>> +             };
>> +     };
>> +};
>
> _______________________________________________
> Alsa-devel mailing list
> Alsa-devel at alsa-project.org
> http://mailman.alsa-project.org/mailman/listinfo/alsa-devel


From heiko at sntech.de  Tue May 17 02:36:23 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 May 2016 11:36:23 +0200
Subject: [alsa-devel] [PATCH v2 4/5] ARM: dts: rockchip: Add shared file
 for audio related nodes for veyron boards
In-Reply-To: <CAFqH_51XmijOmfY2K1Yxcq1=x8T6m5nC0C5_2Qz-7FVR02HrMA@mail.gmail.com>
References: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
 <1769207.YFf2RsNhBy@phil>
 <CAFqH_51XmijOmfY2K1Yxcq1=x8T6m5nC0C5_2Qz-7FVR02HrMA@mail.gmail.com>
Message-ID: <4872705.Eu1B24CGhn@phil>

Am Dienstag, 17. Mai 2016, 10:14:55 schrieb Enric Balletbo Serra:
> Hi Heiko,
> 
> 2016-05-16 0:06 GMT+02:00 Heiko Stuebner <heiko at sntech.de>:
> > Am Montag, 9. Mai 2016, 12:46:34 schrieb Enric Balletbo i Serra:
> >> Set i2s block to "okay", add sound node for max98090 with gpios for
> >> HP and Mic detect and pinctrl, and add a max98090 device and ts3a227e
> >> to
> >> the correct i2c bus.
> >> 
> >> Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
> > 
> > I only got a "applied" reply from Marks scripts for patch 3/5, so only
> > today saw that all 3 actually got applied.
> > 
> > Anyway, I've applied this to my dts32-branch for 4.8 now [0] with some
> > modifications regarding
> > - the commit subject+message
> > - ordering
> > - io_domains access (via the phandle now)
> > - regulator suspend property
> > so maybe take a look and holler if you see a mistake.
> 
> The changes looks good to me, thanks.
> 
> > I was able to get audio over the headphones (so definitly an
> > improvement), but so far not over the built-in speakers. Did you need
> > to do something special in the configuration for this?
> 
> I added an UCM file [1] to my setup to test this and tested as follows
> (you can also use alsamixer but as you know this is not safe though ;)
> )
> 
> # enable the speaker at bootup:
> alsaucm -c ROCKCHIP-I2S set _verb HiFi
> # set speaker to half loudness:
> amixer set Speaker 50%
> # play something
> aplay music.wav
> # enable headphones (disable speaker):
> alsaucm -c ROCKCHIP-I2S set _verb HiFi set _enadev Headphone
> # set headphones to half loudness:
> amixer set Headphone 50%
> # play something
> aplay music.wav
> # disable headphones (enable speaker):
> alsaucm -c ROCKCHIP-I2S set _verb HiFi set _disdev Headphone

woohoo ... sound on the speakers :-D

Thanks for the hints
Heiko


From heiko at sntech.de  Tue May 17 06:30:28 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 May 2016 15:30:28 +0200
Subject: [alsa-devel] [PATCH v2 4/5] ARM: dts: rockchip: Add shared file
 for audio related nodes for veyron boards
In-Reply-To: <4872705.Eu1B24CGhn@phil>
References: <1462790795-25345-1-git-send-email-enric.balletbo@collabora.com>
 <CAFqH_51XmijOmfY2K1Yxcq1=x8T6m5nC0C5_2Qz-7FVR02HrMA@mail.gmail.com>
 <4872705.Eu1B24CGhn@phil>
Message-ID: <14374712.skXTGdLur6@phil>

Am Dienstag, 17. Mai 2016, 11:36:23 schrieb Heiko Stuebner:
> Am Dienstag, 17. Mai 2016, 10:14:55 schrieb Enric Balletbo Serra:
> > Hi Heiko,
> > 
> > 2016-05-16 0:06 GMT+02:00 Heiko Stuebner <heiko at sntech.de>:
> > > Am Montag, 9. Mai 2016, 12:46:34 schrieb Enric Balletbo i Serra:
> > >> Set i2s block to "okay", add sound node for max98090 with gpios for
> > >> HP and Mic detect and pinctrl, and add a max98090 device and ts3a227e
> > >> to
> > >> the correct i2c bus.
> > >> 
> > >> Signed-off-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>
> > > 
> > > I only got a "applied" reply from Marks scripts for patch 3/5, so only
> > > today saw that all 3 actually got applied.
> > > 
> > > Anyway, I've applied this to my dts32-branch for 4.8 now [0] with some
> > > modifications regarding
> > > - the commit subject+message
> > > - ordering
> > > - io_domains access (via the phandle now)
> > > - regulator suspend property
> > > so maybe take a look and holler if you see a mistake.
> > 
> > The changes looks good to me, thanks.
> > 
> > > I was able to get audio over the headphones (so definitly an
> > > improvement), but so far not over the built-in speakers. Did you need
> > > to do something special in the configuration for this?
> > 
> > I added an UCM file [1] to my setup to test this and tested as follows
> > (you can also use alsamixer but as you know this is not safe though ;)
> > )
> > 
> > # enable the speaker at bootup:
> > alsaucm -c ROCKCHIP-I2S set _verb HiFi
> > # set speaker to half loudness:
> > amixer set Speaker 50%
> > # play something
> > aplay music.wav
> > # enable headphones (disable speaker):
> > alsaucm -c ROCKCHIP-I2S set _verb HiFi set _enadev Headphone
> > # set headphones to half loudness:
> > amixer set Headphone 50%
> > # play something
> > aplay music.wav
> > # disable headphones (enable speaker):
> > alsaucm -c ROCKCHIP-I2S set _verb HiFi set _disdev Headphone
> 
> woohoo ... sound on the speakers :-D

one thing I'm not sure about is the naming though.

The ucm profiles most likely are board-specific and looking at the other alsa 
ucm subdirs, they really are named after their boards (like daisy-i2s for 
some exynos chromebooks). Hogging ROCKCHIP-I2S for veyron chromebooks seems 
wrong especially wrt. other Rockchip devices. Shouldn't this be named 
VEYRON-I2S or so instead - same on the kernel side probably.


Heiko


From wsy2220 at gmail.com  Tue May 17 08:25:20 2016
From: wsy2220 at gmail.com (Shuyu Wei)
Date: Tue, 17 May 2016 23:25:20 +0800
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
Message-ID: <20160517152520.GA2750@debian-dorm>

Setting the FOR_EMAC flag should be the last step of modifying the buffer
descriptor, or possible racing will occur.

The loop counter i in tx_clean() is not needed, and we need to make sure
it does not clear the finished txbds.

Signed-off-by: Shuyu Wei <sy.w at outlook.com>
---
Changes in v2:
- Remove loop counter in tx_clean and check for unfinished txbds (Ueimor)
- Use dma_wmb() to sync writes (Ueimor)

diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index a3a9392..df3dfef 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -153,9 +153,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 {
 	struct arc_emac_priv *priv = netdev_priv(ndev);
 	struct net_device_stats *stats = &ndev->stats;
-	unsigned int i;
 
-	for (i = 0; i < TX_BD_NUM; i++) {
+	while (priv->txbd_dirty != priv->txbd_curr) {
 		unsigned int *txbd_dirty = &priv->txbd_dirty;
 		struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
 		struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
@@ -685,13 +684,15 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
 	wmb();
 
 	skb_tx_timestamp(skb);
+	priv->tx_buff[*txbd_curr].skb = skb;
+
+	dma_wmb();
 
 	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
 	/* Make sure info word is set */
 	wmb();
 
-	priv->tx_buff[*txbd_curr].skb = skb;
 
 	/* Increment index to point to the next BD */
 	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;



From LinoSanfilippo at gmx.de  Tue May 17 09:36:11 2016
From: LinoSanfilippo at gmx.de (Lino Sanfilippo)
Date: Tue, 17 May 2016 18:36:11 +0200
Subject: Aw: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160517152520.GA2750@debian-dorm>
References: <20160517152520.GA2750@debian-dorm>
Message-ID: <trinity-eed4d6ab-f658-4f47-94ff-5162845ba335-1463502971177@3capp-gmx-bs64>

Hi,

> Von: "Shuyu Wei" <wsy2220 at gmail.com>
> @@ -685,13 +684,15 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
>  	wmb();
>  
>  	skb_tx_timestamp(skb);
> +	priv->tx_buff[*txbd_curr].skb = skb;
> +
> +	dma_wmb();
>  
>  	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
>  
>  	/* Make sure info word is set */
>  	wmb();
>  
> -	priv->tx_buff[*txbd_curr].skb = skb;
>  
>  	/* Increment index to point to the next BD */
>  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
> 

I wonder if this is correct. AFAIK a dma_wmb() only guarantees ordering of writes to DMA memory.
The assignment of the skb however is to RAM not to DMA.


Regards,
Lino


From davem at davemloft.net  Tue May 17 11:24:56 2016
From: davem at davemloft.net (David Miller)
Date: Tue, 17 May 2016 14:24:56 -0400 (EDT)
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160517152520.GA2750@debian-dorm>
References: <20160517152520.GA2750@debian-dorm>
Message-ID: <20160517.142456.2247845107325931733.davem@davemloft.net>

From: Shuyu Wei <wsy2220 at gmail.com>
Date: Tue, 17 May 2016 23:25:20 +0800

> diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
> index a3a9392..df3dfef 100644
> --- a/drivers/net/ethernet/arc/emac_main.c
> +++ b/drivers/net/ethernet/arc/emac_main.c
> @@ -153,9 +153,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>  {
>  	struct arc_emac_priv *priv = netdev_priv(ndev);
>  	struct net_device_stats *stats = &ndev->stats;
> -	unsigned int i;
>  
> -	for (i = 0; i < TX_BD_NUM; i++) {
> +	while (priv->txbd_dirty != priv->txbd_curr) {
>  		unsigned int *txbd_dirty = &priv->txbd_dirty;
>  		struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
>  		struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
> @@ -685,13 +684,15 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
>  	wmb();
>  
>  	skb_tx_timestamp(skb);
> +	priv->tx_buff[*txbd_curr].skb = skb;
> +
> +	dma_wmb();
>  
>  	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
>  
>  	/* Make sure info word is set */
>  	wmb();
>  
> -	priv->tx_buff[*txbd_curr].skb = skb;
>  
>  	/* Increment index to point to the next BD */
>  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
> 

These memory barriers do not look correct to me.

dma_wmb() is about visibility between CPU reads/writes and device
accesses to a piece of memory.  But what you're concerned about wrt.
the SKB pointer assignment is CPU to CPU accesses.  Therefore something
like smp_wmb() would be appropriate.

And the wmb() looks like it should be a dma_wmb().


From heiko at sntech.de  Tue May 17 12:48:43 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 May 2016 21:48:43 +0200
Subject: [PATCH] clk: rockchip: initialize flags of clk_init_data in mmc-phase
 clock
Message-ID: <5857488.K3ESyq6uAh@phil>

The flags element of clk_init_data was never initialized for mmc-
phase-clocks resulting in the element containing a random value
and thus possibly enabling unwanted clock flags.

Fixes: 89bf26cbc1a0 ("clk: rockchip: Add support for the mmc clock phases using the framework")
Cc: stable at vger.kernel.org
Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
Found while investigating the critical clock locking in __clk_core_init
as it generated a bunch of warnings due to the (random) flags containing
the critical clock bit in most cases.

I've also already applied this to my fixes branch, so posted for
reference / shouting if it's terrible wrong :-)

 drivers/clk/rockchip/clk-mmc-phase.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c
index bc856f2..4601130 100644
--- a/drivers/clk/rockchip/clk-mmc-phase.c
+++ b/drivers/clk/rockchip/clk-mmc-phase.c
@@ -154,6 +154,7 @@ struct clk *rockchip_clk_register_mmc(const char *name,
 		return ERR_PTR(-ENOMEM);
 
 	init.name = name;
+	init.flags = 0;
 	init.num_parents = num_parents;
 	init.parent_names = parent_names;
 	init.ops = &rockchip_mmc_clk_ops;
-- 
2.6.4




From heiko at sntech.de  Tue May 17 14:10:51 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 May 2016 23:10:51 +0200
Subject: [PATCH 1/2] clk: rockchip: mark rk3399 GIC clocks as critical
In-Reply-To: <1463164937-91089-1-git-send-email-briannorris@chromium.org>
References: <1463164937-91089-1-git-send-email-briannorris@chromium.org>
Message-ID: <2111538.t2M7m4hXj2@phil>

Am Freitag, 13. Mai 2016, 11:42:16 schrieb Brian Norris:
> We never want to kill the GIC.
> 
> Noticed when making other clock fixups, and seeing the newly-constructed
> clock tree try to disable cpll, where we had this parent structure:
> 
>   aclk_gic <------\
> 
>                   |--- aclk_gic_pre <-- cpll <-- pll_cpll
> 
>   aclk_gic_noc <--/
> 
> Signed-off-by: Brian Norris <briannorris at chromium.org>

applied both patches to my clk-fixes branch with Dougs review-tags.


Thanks
Heiko


From heiko at sntech.de  Tue May 17 14:56:44 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 17 May 2016 23:56:44 +0200
Subject: [PATCH 1/2] Revert "clk: rockchip: reset init state before mmc
 card initialization"
In-Reply-To: <1463076197-15900-1-git-send-email-dianders@chromium.org>
References: <1463076197-15900-1-git-send-email-dianders@chromium.org>
Message-ID: <1546506.kPA2J5E1Tb@phil>

Am Donnerstag, 12. Mai 2016, 11:03:16 schrieb Douglas Anderson:
> This reverts commit 7a03fe6f48f3 ("clk: rockchip: reset init state
> before mmc card initialization").
> 
> Though not totally obvious from the commit message nor from the source
> code, that commit appears to be trying to reset the "_drv" MMC clocks to
> 90 degrees (note that the "_sample" MMC clocks have a shift of 0 so are
> not touched).
> 
> The major problem here is that it doesn't properly reset things.  The
> phase is a two bit field and the commit only touches one of the two
> bits.  Thus the commit had the following affect:
> - phase   0  => phase  90
> - phase  90  => phase  90
> - phase 180  => phase 270
> - phase 270  => phase 270
> 
> Things get even weirder if you happen to have a bootloader that was
> actually using delay elements (should be no reason to, but you never
> know), since those are additional bits that weren't touched by the
> original patch.
> 
> This is unlikely to be what we actually want.  Checking on rk3288-veyron
> devices, I can see that the bootloader leaves these clocks as:
> - emmc:  phase 180
> - sdmmc: phase 90
> - sdio0: phase 90
> 
> Thus on rk3288-veyron devices the commit we're reverting had the effect
> of changing the eMMC clock to phase 270.  This probably explains the
> scattered reports I've heard of eMMC devices not working on some veyron
> devices when using the upstream kernel.
> 
> The original commit was presumably made because previously the kernel
> didn't touch the "_drv" phase at all and relied on whatever value was
> there when the kernel started.  If someone was using a bootloader that
> touched the "_drv" phase then, indeed, we should have code in the kernel
> to fix that.  ...and also, to get ideal timings, we should also have the
> kernel change the phase depending on the speed mode.  In fact, that's
> the subject of a recent patch I posted at
> <https://patchwork.kernel.org/patch/9075141/>.
> 
> Ideally, we should take both the patch posted to dw_mmc and this
> revert.  Since those will likely go through different trees, here I
> describe behavior with the combos:
> 
> 1. Just this revert: likely will fix rk3288-veyron eMMC on some devices
>    + other cases; might break someone with a strange bootloader that
>    sets the phase to 0 or one that uses delay elements (pretty
>    unpredicable what would happen in that case).
> 2. Just dw_mmc patch: fixes everyone.  Effectly the dw_mmc patch will
>    totally override the broken patch and fix everything.
> 3. Both patches: fixes everyone.  Once dw_mmc is initting properly then
>    any defaults from the clock code doesn't mattery.
> 
> Fixes: 7a03fe6f48f3 ("clk: rockchip: reset init state before mmc card
> initialization") Signed-off-by: Douglas Anderson <dianders at chromium.org>

I've tested this revert myself on rk3288-veyron-jerry and rk3288-firefly 
[everything still works] and have put it temporarily into my clk-fixes branch 
to hopefully get a report from kernelci for rk3288-rock2, but may drop it 
again if necessary.


Heiko


From romieu at fr.zoreil.com  Tue May 17 17:01:53 2016
From: romieu at fr.zoreil.com (Francois Romieu)
Date: Wed, 18 May 2016 02:01:53 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160517.142456.2247845107325931733.davem@davemloft.net>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
Message-ID: <20160518000153.GA21757@electric-eye.fr.zoreil.com>

David Miller <davem at davemloft.net> :
> From: Shuyu Wei <wsy2220 at gmail.com>
> Date: Tue, 17 May 2016 23:25:20 +0800
> 
> > diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
> > index a3a9392..df3dfef 100644
> > --- a/drivers/net/ethernet/arc/emac_main.c
> > +++ b/drivers/net/ethernet/arc/emac_main.c
> > @@ -153,9 +153,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
> >  {
> >  	struct arc_emac_priv *priv = netdev_priv(ndev);
> >  	struct net_device_stats *stats = &ndev->stats;
> > -	unsigned int i;
> >  
> > -	for (i = 0; i < TX_BD_NUM; i++) {
> > +	while (priv->txbd_dirty != priv->txbd_curr) {
> >  		unsigned int *txbd_dirty = &priv->txbd_dirty;
> >  		struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
> >  		struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
> > @@ -685,13 +684,15 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
> >  	wmb();
> >  
> >  	skb_tx_timestamp(skb);
> > +	priv->tx_buff[*txbd_curr].skb = skb;
> > +
> > +	dma_wmb();
> >  
> >  	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
> >  
> >  	/* Make sure info word is set */
> >  	wmb();
> >  
> > -	priv->tx_buff[*txbd_curr].skb = skb;
> >  
> >  	/* Increment index to point to the next BD */
> >  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
> > 
> 
> These memory barriers do not look correct to me.
> 
> dma_wmb() is about visibility between CPU reads/writes and device
> accesses to a piece of memory.  But what you're concerned about wrt.
> the SKB pointer assignment is CPU to CPU accesses.  Therefore something
> like smp_wmb() would be appropriate.

Something like:

 	skb_tx_timestamp(skb);

	/* CPU write vs device access. Must be done before releasing control
	 * of the descriptor (*info).
	 */
	dma_wmb();

	priv->tx_buff[*txbd_curr].skb = skb;

	/* CPU arc_emac_tx_clean vs CPU arc_emac_tx. Must be done before
	 * index (tx_curr) update. Does not necessarily deserves to be done
	 * before releasing control of the descriptor (*info) due to
	 * descriptor vs index ordering.
	 *
	 * FIXME: missing smp_rmb before the while loop in arc_emac_tx_clean.
	 */
	smp_wmb();

 	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);

	/* local descriptor (*info) update vs index (tx_curr) update. */
 	wmb();

	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;

	smp_mb();	// The driver alreay contains this one.

The smp_wmb() and wmb() could be made side-by-side once *info is
updated but I don't see the adequate idiom to improve the smp_wmb + wmb
combo. :o/

> And the wmb() looks like it should be a dma_wmb().

I see two points against it:
- it could be too late for skb_tx_timestamp().
- arc_emac_tx_clean must not see an index update before the device
  got a chance to acquire the descriptor. arc_emac_tx_clean can't
  tell the difference between an about-to-be-released descriptor
  and a returned-from-device one.

-- 
Ueimor


From dianders at chromium.org  Tue May 17 17:47:34 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 17 May 2016 17:47:34 -0700
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
Message-ID: <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>

Jaehoon,

On Mon, Mar 30, 2015 at 8:47 AM, Doug Anderson <dianders at chromium.org> wrote:
> Jaehoon,
>
> On Sun, Mar 29, 2015 at 5:55 PM, Jaehoon Chung <jh80.chung at samsung.com> wrote:
>> Dear Doug,
>>
>> I'm considering to control HLE error..So holding this patch.
>> If this is absolutely necessary patch, let me know, plz.
>>
>> Best Regards,
>> Jaehoon Chung
>
> Sounds OK.  I have certainly applied this locally and the driver isn't
> robust against insertions / removals without it, but once the card is
> inserted things are OK so it's probably not urgent that it be applied
> upstream.  Hopefully we can figure out a better solution...

I'm now testing a nice new rebased kernel and I'm hitting this again.

Of course I'll just pick my same patch to my new kernel tree, but
since it's been a year and nobody has done anything better, would you
consider landing my patch?  It is certainly better than nothing.

-Doug


From shawn.lin at kernel-upstream.org  Tue May 17 18:59:41 2016
From: shawn.lin at kernel-upstream.org (Shawn Lin)
Date: Wed, 18 May 2016 09:59:41 +0800
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
 <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
Message-ID: <573BCC8D.5090606@kernel-upstream.org>

Hi Doug,

On 2016-5-18 8:47, Doug Anderson wrote:
> Jaehoon,
>
> On Mon, Mar 30, 2015 at 8:47 AM, Doug Anderson <dianders at chromium.org> wrote:
>> Jaehoon,
>>
>> On Sun, Mar 29, 2015 at 5:55 PM, Jaehoon Chung <jh80.chung at samsung.com> wrote:
>>> Dear Doug,
>>>
>>> I'm considering to control HLE error..So holding this patch.
>>> If this is absolutely necessary patch, let me know, plz.
>>>
>>> Best Regards,
>>> Jaehoon Chung
>> Sounds OK.  I have certainly applied this locally and the driver isn't
>> robust against insertions / removals without it, but once the card is
>> inserted things are OK so it's probably not urgent that it be applied
>> upstream.  Hopefully we can figure out a better solution...
> I'm now testing a nice new rebased kernel and I'm hitting this again.
>
> Of course I'll just pick my same patch to my new kernel tree, but
> since it's been a year and nobody has done anything better, would you
> consider landing my patch?  It is certainly better than nothing.

Could you try this patch to see if you can still find HLE?

@@ -2356,12 +2356,22 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
  static void dw_mci_handle_cd(struct dw_mci *host)
  {
         int i;
+       int present;

         for (i = 0; i < host->num_slots; i++) {
                 struct dw_mci_slot *slot = host->slot[i];

                 if (!slot)
                         continue;

+               present = !(mci_readl(slot->host, CDETECT) & (1 << slot->id));
+               if (present)
+                       set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+               else
+                       clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);

                 if (slot->mmc->ops->card_event)
                         slot->mmc->ops->card_event(slot->mmc);


>
> -Doug
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>



From jh80.chung at samsung.com  Tue May 17 19:08:53 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Wed, 18 May 2016 11:08:53 +0900
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
 <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
Message-ID: <573BCEB5.8020905@samsung.com>

On 05/18/2016 09:47 AM, Doug Anderson wrote:
> Jaehoon,
> 
> On Mon, Mar 30, 2015 at 8:47 AM, Doug Anderson <dianders at chromium.org> wrote:
>> Jaehoon,
>>
>> On Sun, Mar 29, 2015 at 5:55 PM, Jaehoon Chung <jh80.chung at samsung.com> wrote:
>>> Dear Doug,
>>>
>>> I'm considering to control HLE error..So holding this patch.
>>> If this is absolutely necessary patch, let me know, plz.
>>>
>>> Best Regards,
>>> Jaehoon Chung
>>
>> Sounds OK.  I have certainly applied this locally and the driver isn't
>> robust against insertions / removals without it, but once the card is
>> inserted things are OK so it's probably not urgent that it be applied
>> upstream.  Hopefully we can figure out a better solution...
> 
> I'm now testing a nice new rebased kernel and I'm hitting this again.
> 
> Of course I'll just pick my same patch to my new kernel tree, but
> since it's been a year and nobody has done anything better, would you
> consider landing my patch?  It is certainly better than nothing.

Sure, it's right.
I think that main reason of HLE is wait_prvdata_complete. (I'm guessing..)
On other hands, dwmmc controller is handling something wrong. (I found that HLE is occurred the similar case.)
After find the main solution, it's not bad that your patch is applied on dwmmc controller.

Ulf have sent PR for next..So if we needs to apply this, i will apply on fix.

Best Regards,
Jaehoon Chung

> 
> -Doug
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 



From dianders at chromium.org  Tue May 17 21:12:16 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 17 May 2016 21:12:16 -0700
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <573BCC8D.5090606@kernel-upstream.org>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
 <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
 <573BCC8D.5090606@kernel-upstream.org>
Message-ID: <CAD=FV=VneQR3wurjezBkRhtQiH+q-FfhDN8=Ym=XqtZpVmsdUw@mail.gmail.com>

Hi,

On Tue, May 17, 2016 at 6:59 PM, Shawn Lin
<shawn.lin at kernel-upstream.org> wrote:
> Could you try this patch to see if you can still find HLE?
>
> @@ -2356,12 +2356,22 @@ static void dw_mci_cmd_interrupt(struct dw_mci
> *host, u32 status)
>  static void dw_mci_handle_cd(struct dw_mci *host)
>  {
>         int i;
> +       int present;
>
>         for (i = 0; i < host->num_slots; i++) {
>                 struct dw_mci_slot *slot = host->slot[i];
>
>                 if (!slot)
>                         continue;
>
> +               present = !(mci_readl(slot->host, CDETECT) & (1 <<
> slot->id));
> +               if (present)
> +                       set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
> +               else
> +                       clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);

No, because we don't use the builtin card detect on veyron.  ;)

We use GPIO card detect because we didn't like the way JTAG and SD
interacted.  Also on rk3288 the builtin card detect line had the wrong
voltage domain (you couldn't detect a card when the IO lines were
powered off).  The builtin card detect line is always driven low on
veyron.


I'm nearly certain that the root cause of my HLE errors is actually
related to the same problem addressed by the commit 7c5209c315ea
("mmc: core: Increase delay for voltage to stabilize from 3.3V to
1.8V").  I think that on minnie we're still on the hairy edge and
sometimes the line doesn't transition fast enough.

It appears that increasing this to 30ms avoids the HLE errors.

I _think_ I can actually fully fix this properly by temporarily
engaging the internal pull-ups while the voltage switch is happening.
This will bleed away the voltage just a little bit faster (since lines
are driven low here).  I'll try to confirm that.


In any case, it seems like we should take this patch since (without
this patch) the failure case when you get HLE errors is that the
interrupt controller fires over and over again (with no printouts) and
your system stalls with no error messages.

-Doug


From dianders at chromium.org  Tue May 17 21:13:12 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 17 May 2016 21:13:12 -0700
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <573BCEB5.8020905@samsung.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
 <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
 <573BCEB5.8020905@samsung.com>
Message-ID: <CAD=FV=XFUKXRRRyVLOTV1ORtYfG1ngEqic-CYLp9S=C=8eJYkw@mail.gmail.com>

Hi,

On Tue, May 17, 2016 at 7:08 PM, Jaehoon Chung <jh80.chung at samsung.com> wrote:
> On 05/18/2016 09:47 AM, Doug Anderson wrote:
>> Jaehoon,
>>
>> On Mon, Mar 30, 2015 at 8:47 AM, Doug Anderson <dianders at chromium.org> wrote:
>>> Jaehoon,
>>>
>>> On Sun, Mar 29, 2015 at 5:55 PM, Jaehoon Chung <jh80.chung at samsung.com> wrote:
>>>> Dear Doug,
>>>>
>>>> I'm considering to control HLE error..So holding this patch.
>>>> If this is absolutely necessary patch, let me know, plz.
>>>>
>>>> Best Regards,
>>>> Jaehoon Chung
>>>
>>> Sounds OK.  I have certainly applied this locally and the driver isn't
>>> robust against insertions / removals without it, but once the card is
>>> inserted things are OK so it's probably not urgent that it be applied
>>> upstream.  Hopefully we can figure out a better solution...
>>
>> I'm now testing a nice new rebased kernel and I'm hitting this again.
>>
>> Of course I'll just pick my same patch to my new kernel tree, but
>> since it's been a year and nobody has done anything better, would you
>> consider landing my patch?  It is certainly better than nothing.
>
> Sure, it's right.
> I think that main reason of HLE is wait_prvdata_complete. (I'm guessing..)
> On other hands, dwmmc controller is handling something wrong. (I found that HLE is occurred the similar case.)
> After find the main solution, it's not bad that your patch is applied on dwmmc controller.
>
> Ulf have sent PR for next..So if we needs to apply this, i will apply on fix.

It's not new, so I'd say just queue it up for the next version
whenever it's convenient.

-Doug


From shawn.lin at rock-chips.com  Wed May 18 00:25:12 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Wed, 18 May 2016 15:25:12 +0800
Subject: [PATCH 1/2] Revert "clk: rockchip: reset init state before mmc
 card initialization"
In-Reply-To: <1463076197-15900-1-git-send-email-dianders@chromium.org>
References: <1463076197-15900-1-git-send-email-dianders@chromium.org>
Message-ID: <573C18D8.5050508@rock-chips.com>

On 2016-5-13 2:03, Douglas Anderson wrote:
> This reverts commit 7a03fe6f48f3 ("clk: rockchip: reset init state
> before mmc card initialization").
>
> Though not totally obvious from the commit message nor from the source
> code, that commit appears to be trying to reset the "_drv" MMC clocks to
> 90 degrees (note that the "_sample" MMC clocks have a shift of 0 so are
> not touched).
>
> The major problem here is that it doesn't properly reset things.  The
> phase is a two bit field and the commit only touches one of the two
> bits.  Thus the commit had the following affect:
> - phase   0  => phase  90
> - phase  90  => phase  90
> - phase 180  => phase 270
> - phase 270  => phase 270
>
> Things get even weirder if you happen to have a bootloader that was
> actually using delay elements (should be no reason to, but you never
> know), since those are additional bits that weren't touched by the
> original patch.
>
> This is unlikely to be what we actually want.  Checking on rk3288-veyron
> devices, I can see that the bootloader leaves these clocks as:
> - emmc:  phase 180
> - sdmmc: phase 90
> - sdio0: phase 90
>
> Thus on rk3288-veyron devices the commit we're reverting had the effect
> of changing the eMMC clock to phase 270.  This probably explains the
> scattered reports I've heard of eMMC devices not working on some veyron
> devices when using the upstream kernel.
>
> The original commit was presumably made because previously the kernel
> didn't touch the "_drv" phase at all and relied on whatever value was
> there when the kernel started.  If someone was using a bootloader that
> touched the "_drv" phase then, indeed, we should have code in the kernel
> to fix that.  ...and also, to get ideal timings, we should also have the
> kernel change the phase depending on the speed mode.  In fact, that's
> the subject of a recent patch I posted at
> <https://patchwork.kernel.org/patch/9075141/>.
>
> Ideally, we should take both the patch posted to dw_mmc and this
> revert.  Since those will likely go through different trees, here I
> describe behavior with the combos:
>
> 1. Just this revert: likely will fix rk3288-veyron eMMC on some devices
>     + other cases; might break someone with a strange bootloader that
>     sets the phase to 0 or one that uses delay elements (pretty
>     unpredicable what would happen in that case).
> 2. Just dw_mmc patch: fixes everyone.  Effectly the dw_mmc patch will
>     totally override the broken patch and fix everything.
> 3. Both patches: fixes everyone.  Once dw_mmc is initting properly then
>     any defaults from the clock code doesn't mattery.
>
> Fixes: 7a03fe6f48f3 ("clk: rockchip: reset init state before mmc card initialization")
> Signed-off-by: Douglas Anderson <dianders at chromium.org>

Thanks for this fix.

Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>

> ---
>   drivers/clk/rockchip/clk-mmc-phase.c | 11 -----------
>   1 file changed, 11 deletions(-)
>
> diff --git a/drivers/clk/rockchip/clk-mmc-phase.c b/drivers/clk/rockchip/clk-mmc-phase.c
> index bc856f21f6b2..5b18265c2306 100644
> --- a/drivers/clk/rockchip/clk-mmc-phase.c
> +++ b/drivers/clk/rockchip/clk-mmc-phase.c
> @@ -41,8 +41,6 @@ static unsigned long rockchip_mmc_recalc(struct clk_hw *hw,
>   #define ROCKCHIP_MMC_DEGREE_MASK 0x3
>   #define ROCKCHIP_MMC_DELAYNUM_OFFSET 2
>   #define ROCKCHIP_MMC_DELAYNUM_MASK (0xff << ROCKCHIP_MMC_DELAYNUM_OFFSET)
> -#define ROCKCHIP_MMC_INIT_STATE_RESET 0x1
> -#define ROCKCHIP_MMC_INIT_STATE_SHIFT 1
>
>   #define PSECS_PER_SEC 1000000000000LL
>
> @@ -162,15 +160,6 @@ struct clk *rockchip_clk_register_mmc(const char *name,
>   	mmc_clock->reg = reg;
>   	mmc_clock->shift = shift;
>
> -	/*
> -	 * Assert init_state to soft reset the CLKGEN
> -	 * for mmc tuning phase and degree
> -	 */
> -	if (mmc_clock->shift == ROCKCHIP_MMC_INIT_STATE_SHIFT)
> -		writel(HIWORD_UPDATE(ROCKCHIP_MMC_INIT_STATE_RESET,
> -				     ROCKCHIP_MMC_INIT_STATE_RESET,
> -				     mmc_clock->shift), mmc_clock->reg);
> -
>   	clk = clk_register(NULL, &mmc_clock->hw);
>   	if (IS_ERR(clk))
>   		kfree(mmc_clock);
>



From shawn.lin at rock-chips.com  Wed May 18 02:14:43 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Wed, 18 May 2016 17:14:43 +0800
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <CAD=FV=VneQR3wurjezBkRhtQiH+q-FfhDN8=Ym=XqtZpVmsdUw@mail.gmail.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
 <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
 <573BCC8D.5090606@kernel-upstream.org>
 <CAD=FV=VneQR3wurjezBkRhtQiH+q-FfhDN8=Ym=XqtZpVmsdUw@mail.gmail.com>
Message-ID: <573C3283.1040606@rock-chips.com>

Hi

On 2016-5-18 12:12, Doug Anderson wrote:
> Hi,
>
> On Tue, May 17, 2016 at 6:59 PM, Shawn Lin
> <shawn.lin at kernel-upstream.org> wrote:
>> Could you try this patch to see if you can still find HLE?
>>
>> @@ -2356,12 +2356,22 @@ static void dw_mci_cmd_interrupt(struct dw_mci
>> *host, u32 status)
>>   static void dw_mci_handle_cd(struct dw_mci *host)
>>   {
>>          int i;
>> +       int present;
>>
>>          for (i = 0; i < host->num_slots; i++) {
>>                  struct dw_mci_slot *slot = host->slot[i];
>>
>>                  if (!slot)
>>                          continue;
>>
>> +               present = !(mci_readl(slot->host, CDETECT) & (1 <<
>> slot->id));
>> +               if (present)
>> +                       set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>> +               else
>> +                       clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>
> No, because we don't use the builtin card detect on veyron.  ;)
>
> We use GPIO card detect because we didn't like the way JTAG and SD
> interacted.  Also on rk3288 the builtin card detect line had the wrong
> voltage domain (you couldn't detect a card when the IO lines were
> powered off).  The builtin card detect line is always driven low on
> veyron.

Okay, I see.

>
>
> I'm nearly certain that the root cause of my HLE errors is actually
> related to the same problem addressed by the commit 7c5209c315ea
> ("mmc: core: Increase delay for voltage to stabilize from 3.3V to
> 1.8V").  I think that on minnie we're still on the hairy edge and
> sometimes the line doesn't transition fast enough.

Things are not so simple from your details.

I was not enabling SD3.0 support, then I also found HLE sometimes.
So it seems commit 7c5209c315ea does not contibute to this phenomenon.

The scenario looks like:
remove sd-card -> mmc_sd_detect -> send status(CMD13) ->power_off ->
set_ios -> setup_bus -> disabled clk , then HLE irq storm coming

 From the code of dw_mci_prepare_command:
SDMMC_CMD_PRV_DAT_WAIT will not be used for CMD13, so we don't
wait_busy here, then cmd code is loding into queue of dw_mmc but
still failing send out because it's in busy?

With my patch, things go well:
remove sd-card -> clear bit of DW_MMC_CARD_PRESENT  -> send
status(CMD13) return directly -> power_off -> set_ios -> setup_bus -> 
disable clk

So why should we allow inquiry of card status if we sure the card is
removed? I mean no any further cmds should be delivered.

And another question: should we wait busy for cmd13?

>
> It appears that increasing this to 30ms avoids the HLE errors.
>
> I _think_ I can actually fully fix this properly by temporarily
> engaging the internal pull-ups while the voltage switch is happening.
> This will bleed away the voltage just a little bit faster (since lines
> are driven low here).  I'll try to confirm that.
>
>
> In any case, it seems like we should take this patch since (without
> this patch) the failure case when you get HLE errors is that the
> interrupt controller fires over and over again (with no printouts) and
> your system stalls with no error messages.

Sure, at least we need to address this irq storm...

>
> -Doug
>
>
>



From wxt at rock-chips.com  Wed May 18 07:41:50 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 18 May 2016 22:41:50 +0800
Subject: [PATCH] arm64: dts: rockchip: fixes the gic400 2nd region size for
 rk3368
Message-ID: <1463582510-29156-1-git-send-email-wxt@rock-chips.com>

The 2nd additional region is the GIC virtual cpu interface register
base and size.

As the gic400 of rk3368 says, the cpu interface register map as below

:

-0x0000 GICC_CTRL
.
.
.
-0x00fc GICC_IIDR
-0x1000 GICC_IDR

Obviously, the region size should be greater than 0x1000.
So we should make sure to include the GICC_IDR since the kernel will access
it in some cases.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Heiko Stuebner <heiko at sntech.de>
Cc: linux-arm-kernel at lists.infradead.org
Cc: linux-rockchip at lists.infradead.org

---

 arch/arm64/boot/dts/rockchip/rk3368.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
index 8b4a7c9..080203e 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
@@ -670,7 +670,7 @@
 		#address-cells = <0>;
 
 		reg = <0x0 0xffb71000 0x0 0x1000>,
-		      <0x0 0xffb72000 0x0 0x1000>,
+		      <0x0 0xffb72000 0x0 0x2000>,
 		      <0x0 0xffb74000 0x0 0x2000>,
 		      <0x0 0xffb76000 0x0 0x2000>;
 		interrupts = <GIC_PPI 9
-- 
2.7.4



From dianders at chromium.org  Wed May 18 10:37:52 2016
From: dianders at chromium.org (Doug Anderson)
Date: Wed, 18 May 2016 10:37:52 -0700
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <573C3283.1040606@rock-chips.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
 <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
 <573BCC8D.5090606@kernel-upstream.org>
 <CAD=FV=VneQR3wurjezBkRhtQiH+q-FfhDN8=Ym=XqtZpVmsdUw@mail.gmail.com>
 <573C3283.1040606@rock-chips.com>
Message-ID: <CAD=FV=UoT2GRYWJWXEn_ccvKGgC+PzQM_BCtLHAa7jxzbaQ9SA@mail.gmail.com>

Hi,

On Wed, May 18, 2016 at 2:14 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> Hi
>
>
> On 2016-5-18 12:12, Doug Anderson wrote:
>>
>> Hi,
>>
>> On Tue, May 17, 2016 at 6:59 PM, Shawn Lin
>> <shawn.lin at kernel-upstream.org> wrote:
>>>
>>> Could you try this patch to see if you can still find HLE?
>>>
>>> @@ -2356,12 +2356,22 @@ static void dw_mci_cmd_interrupt(struct dw_mci
>>> *host, u32 status)
>>>   static void dw_mci_handle_cd(struct dw_mci *host)
>>>   {
>>>          int i;
>>> +       int present;
>>>
>>>          for (i = 0; i < host->num_slots; i++) {
>>>                  struct dw_mci_slot *slot = host->slot[i];
>>>
>>>                  if (!slot)
>>>                          continue;
>>>
>>> +               present = !(mci_readl(slot->host, CDETECT) & (1 <<
>>> slot->id));
>>> +               if (present)
>>> +                       set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>> +               else
>>> +                       clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>
>>
>> No, because we don't use the builtin card detect on veyron.  ;)
>>
>> We use GPIO card detect because we didn't like the way JTAG and SD
>> interacted.  Also on rk3288 the builtin card detect line had the wrong
>> voltage domain (you couldn't detect a card when the IO lines were
>> powered off).  The builtin card detect line is always driven low on
>> veyron.
>
>
> Okay, I see.
>
>>
>>
>> I'm nearly certain that the root cause of my HLE errors is actually
>> related to the same problem addressed by the commit 7c5209c315ea
>> ("mmc: core: Increase delay for voltage to stabilize from 3.3V to
>> 1.8V").  I think that on minnie we're still on the hairy edge and
>> sometimes the line doesn't transition fast enough.
>
>
> Things are not so simple from your details.
>
> I was not enabling SD3.0 support, then I also found HLE sometimes.
> So it seems commit 7c5209c315ea does not contibute to this phenomenon.

Just to clarify, in my case commit 7c5209c315ea didn't make the
problem worse, but made it better.  Just not better enough.  ;)


> The scenario looks like:
> remove sd-card -> mmc_sd_detect -> send status(CMD13) ->power_off ->
> set_ios -> setup_bus -> disabled clk , then HLE irq storm coming
>
> From the code of dw_mci_prepare_command:
> SDMMC_CMD_PRV_DAT_WAIT will not be used for CMD13, so we don't
> wait_busy here, then cmd code is loding into queue of dw_mmc but
> still failing send out because it's in busy?
>
> With my patch, things go well:
> remove sd-card -> clear bit of DW_MMC_CARD_PRESENT  -> send
> status(CMD13) return directly -> power_off -> set_ios -> setup_bus ->
> disable clk
>
> So why should we allow inquiry of card status if we sure the card is
> removed? I mean no any further cmds should be delivered.

Quite honestly just dealing with the HLE error (my patch or
equivalent) might be a sane solution for the problem you describe.

dw_mmc needs to be able to work with an external card detect GPIO.
It's been part of the dw_mmc driver for a long time and is (in fact)
in use upstream at least by rk3288-veyron.  Any solution that only
works for internal card detect is not enough.  Just handling the HLE
error to deal with the interrupt storm and then letting Linux remove
the card (because of the card detect interrupt) seems totally OK to
me.

Note: I'd be very curious if your problems get better if you disable
the "grf_force_jtag" bit in the GRF.  If you're using the builtin card
detect and you use the boot default of "grf_force_jtag" then your pins
will be unmuxed behind your back when the card is ejected.  This could
be causing the dw_mmc controller to get confused.


> And another question: should we wait busy for cmd13?

I don't think so.  As I understand it CMD13 uses only the CMD line for
communication and it should be appropriate to send this when the bus
is "busy" (which means that the DATA lines are low).

Also: it seems odd that the HLE IRQ storm didn't come right after the
CMD 13 in your description above.  Are you sure it was the CMD 13 that
caused the HLEs, or could it has been something else?


-Doug


From heiko at sntech.de  Wed May 18 11:01:44 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Wed, 18 May 2016 20:01:44 +0200
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <CAD=FV=UoT2GRYWJWXEn_ccvKGgC+PzQM_BCtLHAa7jxzbaQ9SA@mail.gmail.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <573C3283.1040606@rock-chips.com>
 <CAD=FV=UoT2GRYWJWXEn_ccvKGgC+PzQM_BCtLHAa7jxzbaQ9SA@mail.gmail.com>
Message-ID: <9061286.nTNVjb4bva@phil>

Am Mittwoch, 18. Mai 2016, 10:37:52 schrieb Doug Anderson:
> Note: I'd be very curious if your problems get better if you disable
> the "grf_force_jtag" bit in the GRF.  If you're using the builtin card
> detect and you use the boot default of "grf_force_jtag" then your pins
> will be unmuxed behind your back when the card is ejected.  This could
> be causing the dw_mmc controller to get confused.

On the rk3288, we saw issues with the jtag/sdmmc function and thus disabled 
that altogether in [0]. Not sure if that is a similar problem for you.

Heiko

[0] 
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c9b75d51c940c25587a2ad72ec7ec60490abfb6c



From LinoSanfilippo at gmx.de  Wed May 18 13:29:17 2016
From: LinoSanfilippo at gmx.de (Lino Sanfilippo)
Date: Wed, 18 May 2016 22:29:17 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160518000153.GA21757@electric-eye.fr.zoreil.com>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com>
Message-ID: <573CD09D.1060307@gmx.de>

On 18.05.2016 02:01, Francois Romieu wrote:

> The smp_wmb() and wmb() could be made side-by-side once *info is
> updated but I don't see the adequate idiom to improve the smp_wmb + wmb
> combo. :o/
> 
>> And the wmb() looks like it should be a dma_wmb().
> 
> I see two points against it:
> - it could be too late for skb_tx_timestamp().
> - arc_emac_tx_clean must not see an index update before the device
>   got a chance to acquire the descriptor. arc_emac_tx_clean can't
>   tell the difference between an about-to-be-released descriptor
>   and a returned-from-device one.
> 

Hi,

what about the (only compile tested) code below?

The smp_wmb() in tx function combined with the smp_rmb() in tx_clean ensures
that the CPU running tx_clean sees consistent values for info, data and skb 
(thus no need to check for validity of all three values any more).

The mb() fulfills several tasks:
1. makes sure that DMA writes to descriptor are completed before the HW is
    informed.
2. On multi processor systems: ensures that txbd_curr is updated (this is paired
    with the smp_mb() at the end of tx_clean).
3. Ensure we see the most recent value for tx_dirty. With this we do not have to
    recheck after we stopped the tx queue.


--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -162,8 +162,13 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 		struct sk_buff *skb = tx_buff->skb;
 		unsigned int info = le32_to_cpu(txbd->info);
 
-		if ((info & FOR_EMAC) || !txbd->data || !skb)
+		if (info & FOR_EMAC) {
+			/* Make sure we see consistent values for info, skb
+			 * and data.
+			 */
+			smp_rmb();
 			break;
+		}
 
 		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
 			stats->tx_errors++;
@@ -679,36 +684,33 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
 	dma_unmap_addr_set(&priv->tx_buff[*txbd_curr], addr, addr);
 	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
 
-	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
 
-	/* Make sure pointer to data buffer is set */
-	wmb();
+	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
+	priv->tx_buff[*txbd_curr].skb = skb;
 
-	skb_tx_timestamp(skb);
+	/* Make sure info is set after data and skb with respect to
+	 * other tx_clean().
+	 */
+	smp_wmb();
 
 	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
-	/* Make sure info word is set */
-	wmb();
-
-	priv->tx_buff[*txbd_curr].skb = skb;
-
 	/* Increment index to point to the next BD */
 	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
 
-	/* Ensure that tx_clean() sees the new txbd_curr before
+	/* 1.Ensure that tx_clean() sees the new txbd_curr before
 	 * checking the queue status. This prevents an unneeded wake
 	 * of the queue in tx_clean().
+	 * 2.Ensure that all values are written to RAM and to DMA
+	 * before hardware is informed.
+	 * 3.Ensure we see the most recent value for tx_dirty.
 	 */
-	smp_mb();
+	mb();
 
-	if (!arc_emac_tx_avail(priv)) {
+	if (!arc_emac_tx_avail(priv))
 		netif_stop_queue(ndev);
-		/* Refresh tx_dirty */
-		smp_mb();
-		if (arc_emac_tx_avail(priv))
-			netif_start_queue(ndev);
-	}
+
+	skb_tx_timestamp(skb);
 
 	arc_reg_set(priv, R_STATUS, TXPL_MASK);
 
-- 
2.7.0

Regards,
Lino


From romieu at fr.zoreil.com  Wed May 18 15:55:29 2016
From: romieu at fr.zoreil.com (Francois Romieu)
Date: Thu, 19 May 2016 00:55:29 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <573CD09D.1060307@gmx.de>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com>
 <573CD09D.1060307@gmx.de>
Message-ID: <20160518225529.GA18671@electric-eye.fr.zoreil.com>

Lino Sanfilippo <LinoSanfilippo at gmx.de> :
[...]
> what about the (only compile tested) code below?

I may have misunderstood some parts but it nonetheless seems broken.

> The smp_wmb() in tx function combined with the smp_rmb() in tx_clean ensures
> that the CPU running tx_clean sees consistent values for info, data and skb 
> (thus no need to check for validity of all three values any more).
> The mb() fulfills several tasks:
> 1. makes sure that DMA writes to descriptor are completed before the HW is
>     informed.

"DMA writes" == "CPU writes" ?

> 2. On multi processor systems: ensures that txbd_curr is updated (this is paired
>     with the smp_mb() at the end of tx_clean).

Smells like using barrier side-effects to control smp coherency. It isn't
the recommended style.

> 3. Ensure we see the most recent value for tx_dirty. With this we do not have to
>     recheck after we stopped the tx queue.
> 
> 
> --- a/drivers/net/ethernet/arc/emac_main.c
> +++ b/drivers/net/ethernet/arc/emac_main.c
> @@ -162,8 +162,13 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>  		struct sk_buff *skb = tx_buff->skb;
>  		unsigned int info = le32_to_cpu(txbd->info);
>  
> -		if ((info & FOR_EMAC) || !txbd->data || !skb)
> +		if (info & FOR_EMAC) {
> +			/* Make sure we see consistent values for info, skb
> +			 * and data.
> +			 */
> +			smp_rmb();
>  			break;
> +		}

?

smp_rmb should appear before the variables you want coherency for.

>  
>  		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
>  			stats->tx_errors++;
> @@ -679,36 +684,33 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
>  	dma_unmap_addr_set(&priv->tx_buff[*txbd_curr], addr, addr);
>  	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
>  
> -	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
>  
> -	/* Make sure pointer to data buffer is set */
> -	wmb();
> +	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
> +	priv->tx_buff[*txbd_curr].skb = skb;
>  
> -	skb_tx_timestamp(skb);
> +	/* Make sure info is set after data and skb with respect to
> +	 * other tx_clean().
> +	 */
> +	smp_wmb();
>  
>  	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);

Afaik smp_wmb() does not imply wmb(). So priv->txbd[*txbd_curr].data and
*info (aka priv->txbd[*txbd_curr].info) are not necessarily written in
an orderly manner.

>  
> -	/* Make sure info word is set */
> -	wmb();
> -
> -	priv->tx_buff[*txbd_curr].skb = skb;
> -
>  	/* Increment index to point to the next BD */
>  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;

With this change it's possible that tx_clean() reads new value for
tx_curr and old value (0) for *info.

>  
> -	/* Ensure that tx_clean() sees the new txbd_curr before
> +	/* 1.Ensure that tx_clean() sees the new txbd_curr before
>  	 * checking the queue status. This prevents an unneeded wake
>  	 * of the queue in tx_clean().
> +	 * 2.Ensure that all values are written to RAM and to DMA
> +	 * before hardware is informed.

(I am not sure what "DMA" is supposed to mean here.)

> +	 * 3.Ensure we see the most recent value for tx_dirty.
>  	 */
> -	smp_mb();
> +	mb();
>  
> -	if (!arc_emac_tx_avail(priv)) {
> +	if (!arc_emac_tx_avail(priv))
>  		netif_stop_queue(ndev);
> -		/* Refresh tx_dirty */
> -		smp_mb();
> -		if (arc_emac_tx_avail(priv))
> -			netif_start_queue(ndev);
> -	}

Xmit thread                        | Clean thread

mb();

arc_emac_tx_avail() test with old
tx_dirty - tx_clean has not issued
any mb yet - and new tx_curr

                                     smp_mb();

                                     if (netif_queue_stopped(ndev) && ...
                                             netif_wake_queue(ndev);

netif_stop_queue()

-> queue stopped.

You can't remove the revalidation step.

arc_emac_tx_avail() is essentially pessimistic. Even if arc_emac_tx_avail()
was "right", there would be a tx_clean window between arc_emac_tx_avail()
and netif_stop_queue().

> +
> +	skb_tx_timestamp(skb);

You don't want to issue skb_tx_timestamp after releasing control of the
descriptor (*info = ...): skb may be long gone.

-- 
Ueimor


From david.wu at rock-chips.com  Thu May 19 01:09:13 2016
From: david.wu at rock-chips.com (David.Wu)
Date: Thu, 19 May 2016 16:09:13 +0800
Subject: [PATCH] arm64: dts: rockchip: add i2c nodes for rk3399
In-Reply-To: <1463429371-10950-1-git-send-email-dianders@chromium.org>
References: <1463429371-10950-1-git-send-email-dianders@chromium.org>
Message-ID: <466d93c8-e405-51d7-401d-3d7cbd8560cf@rock-chips.com>

Hi Doug,

? 2016/5/17 4:09, Douglas Anderson ??:
> From: David Wu <david.wu at rock-chips.com>
>
> We've got 9 (count em!) i2c controllers on rk3399, some of which are in
> the PMU power domain and some of which are normal peripherals.  Add them
> all to the main rk3399 dtsi file so future patches can turn them on in
> the board dts files.
>
> Note: by default we try to set the i2c clock rate to 200 MHz so that we
> can achieve good i2c functional clock rates.  200 MHz gives us the
> ability to make very close to 100 kHz / 400 kHz / 1 MHz rates.  If
> boards want to tune clock rates further they can always override.
> Possibly boards could want to tune this if:
> - they wanted to save an infinitesimal amount of power and they knew
>   their i2c bus was slow anyway.  Since we gate the functional clock
>   when the i2c bus is not active, power savings would only be while i2c
>   transfers were happening and probably won't be very big anyway.
> - they wanted to eek out a bit more speed by carefully tuning the source
>   clock to make divisions work out perfectly, accounting for the rise /
>   fall time measured on an actual board.
>
> Note also that we still request 200 MHz for the PMU i2c busses even
> though we expect that we won't make that exactly (currently PPLL is 676
> MHz which gives us 169 MHz).

Yeah, this looks like you got all the right bits in the right places and 
didn't mess it up.
This patch is looking really good to me, thanks for doing it.

>
> Signed-off-by: David Wu <david.wu at rock-chips.com>
> Signed-off-by: Jianqun Xu <jay.xu at rock-chips.com>
> [dianders: wrote desc; put in assigned-clocks; reordered nodes]
> Signed-off-by: Douglas Anderson <dianders at chromium.org>
> ---
> Note: this patch is based upon David Wu's patch series to add rk3399
> support to i2c-rk3x.c and shouldn't land until at least device tree
> bindings land.
>
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi | 144 +++++++++++++++++++++++++++++++
>  1 file changed, 144 insertions(+)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> index 46f325a143b0..753a91728b4c 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -54,6 +54,15 @@
>  	#size-cells = <2>;
>
>  	aliases {
> +		i2c0 = &i2c0;
> +		i2c1 = &i2c1;
> +		i2c2 = &i2c2;
> +		i2c3 = &i2c3;
> +		i2c4 = &i2c4;
> +		i2c5 = &i2c5;
> +		i2c6 = &i2c6;
> +		i2c7 = &i2c7;
> +		i2c8 = &i2c8;
>  		serial0 = &uart0;
>  		serial1 = &uart1;
>  		serial2 = &uart2;
> @@ -272,6 +281,96 @@
>  		};
>  	};
>
> +	i2c1: i2c at ff110000 {
> +		compatible = "rockchip,rk3399-i2c";
> +		reg = <0x0 0xff110000 0x0 0x1000>;
> +		assigned-clocks = <&cru SCLK_I2C1>;
> +		assigned-clock-rates = <200000000>;
> +		clocks = <&cru SCLK_I2C1>, <&cru PCLK_I2C1>;
> +		clock-names = "i2c", "pclk";
> +		interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&i2c1_xfer>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		status = "disabled";
> +	};
> +
> +	i2c2: i2c at ff120000 {
> +		compatible = "rockchip,rk3399-i2c";
> +		reg = <0x0 0xff120000 0x0 0x1000>;
> +		assigned-clocks = <&cru SCLK_I2C2>;
> +		assigned-clock-rates = <200000000>;
> +		clocks = <&cru SCLK_I2C2>, <&cru PCLK_I2C2>;
> +		clock-names = "i2c", "pclk";
> +		interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&i2c2_xfer>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		status = "disabled";
> +	};
> +
> +	i2c3: i2c at ff130000 {
> +		compatible = "rockchip,rk3399-i2c";
> +		reg = <0x0 0xff130000 0x0 0x1000>;
> +		assigned-clocks = <&cru SCLK_I2C3>;
> +		assigned-clock-rates = <200000000>;
> +		clocks = <&cru SCLK_I2C3>, <&cru PCLK_I2C3>;
> +		clock-names = "i2c", "pclk";
> +		interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&i2c3_xfer>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		status = "disabled";
> +	};
> +
> +	i2c5: i2c at ff140000 {
> +		compatible = "rockchip,rk3399-i2c";
> +		reg = <0x0 0xff140000 0x0 0x1000>;
> +		assigned-clocks = <&cru SCLK_I2C5>;
> +		assigned-clock-rates = <200000000>;
> +		clocks = <&cru SCLK_I2C5>, <&cru PCLK_I2C5>;
> +		clock-names = "i2c", "pclk";
> +		interrupts = <GIC_SPI 38 IRQ_TYPE_LEVEL_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&i2c5_xfer>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		status = "disabled";
> +	};
> +
> +	i2c6: i2c at ff150000 {
> +		compatible = "rockchip,rk3399-i2c";
> +		reg = <0x0 0xff150000 0x0 0x1000>;
> +		assigned-clocks = <&cru SCLK_I2C6>;
> +		assigned-clock-rates = <200000000>;
> +		clocks = <&cru SCLK_I2C6>, <&cru PCLK_I2C6>;
> +		clock-names = "i2c", "pclk";
> +		interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&i2c6_xfer>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		status = "disabled";
> +	};
> +
> +	i2c7: i2c at ff160000 {
> +		compatible = "rockchip,rk3399-i2c";
> +		reg = <0x0 0xff160000 0x0 0x1000>;
> +		assigned-clocks = <&cru SCLK_I2C7>;
> +		assigned-clock-rates = <200000000>;
> +		clocks = <&cru SCLK_I2C7>, <&cru PCLK_I2C7>;
> +		clock-names = "i2c", "pclk";
> +		interrupts = <GIC_SPI 36 IRQ_TYPE_LEVEL_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&i2c7_xfer>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		status = "disabled";
> +	};
> +
>  	uart0: serial at ff180000 {
>  		compatible = "rockchip,rk3399-uart", "snps,dw-apb-uart";
>  		reg = <0x0 0xff180000 0x0 0x100>;
> @@ -420,6 +519,51 @@
>  		status = "disabled";
>  	};
>
> +	i2c0: i2c at ff3c0000 {
> +		compatible = "rockchip,rk3399-i2c";
> +		reg = <0x0 0xff3c0000 0x0 0x1000>;
> +		assigned-clocks = <&pmucru SCLK_I2C0_PMU>;
> +		assigned-clock-rates = <200000000>;
> +		clocks = <&pmucru SCLK_I2C0_PMU>, <&pmucru PCLK_I2C0_PMU>;
> +		clock-names = "i2c", "pclk";
> +		interrupts = <GIC_SPI 57 IRQ_TYPE_LEVEL_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&i2c0_xfer>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		status = "disabled";
> +	};
> +
> +	i2c4: i2c at ff3d0000 {
> +		compatible = "rockchip,rk3399-i2c";
> +		reg = <0x0 0xff3d0000 0x0 0x1000>;
> +		assigned-clocks = <&pmucru SCLK_I2C4_PMU>;
> +		assigned-clock-rates = <200000000>;
> +		clocks = <&pmucru SCLK_I2C4_PMU>, <&pmucru PCLK_I2C4_PMU>;
> +		clock-names = "i2c", "pclk";
> +		interrupts = <GIC_SPI 56 IRQ_TYPE_LEVEL_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&i2c4_xfer>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		status = "disabled";
> +	};
> +
> +	i2c8: i2c at ff3e0000 {
> +		compatible = "rockchip,rk3399-i2c";
> +		reg = <0x0 0xff3e0000 0x0 0x1000>;
> +		assigned-clocks = <&pmucru SCLK_I2C8_PMU>;
> +		assigned-clock-rates = <200000000>;
> +		clocks = <&pmucru SCLK_I2C8_PMU>, <&pmucru PCLK_I2C8_PMU>;
> +		clock-names = "i2c", "pclk";
> +		interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
> +		pinctrl-names = "default";
> +		pinctrl-0 = <&i2c8_xfer>;
> +		#address-cells = <1>;
> +		#size-cells = <0>;
> +		status = "disabled";
> +	};
> +
>  	pwm0: pwm at ff420000 {
>  		compatible = "rockchip,rk3399-pwm", "rockchip,rk3288-pwm";
>  		reg = <0x0 0xff420000 0x0 0x10>;
>



From shawn.lin at rock-chips.com  Thu May 19 04:31:53 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 19 May 2016 19:31:53 +0800
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <CAD=FV=UoT2GRYWJWXEn_ccvKGgC+PzQM_BCtLHAa7jxzbaQ9SA@mail.gmail.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
 <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
 <573BCC8D.5090606@kernel-upstream.org>
 <CAD=FV=VneQR3wurjezBkRhtQiH+q-FfhDN8=Ym=XqtZpVmsdUw@mail.gmail.com>
 <573C3283.1040606@rock-chips.com>
 <CAD=FV=UoT2GRYWJWXEn_ccvKGgC+PzQM_BCtLHAa7jxzbaQ9SA@mail.gmail.com>
Message-ID: <10b3dc0e-aebf-664b-b36b-c54692cd9983@rock-chips.com>

Hi,

On 2016/5/19 1:37, Doug Anderson wrote:
> Hi,
>
> On Wed, May 18, 2016 at 2:14 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> Hi
>>
>>
>> On 2016-5-18 12:12, Doug Anderson wrote:
>>>
>>> Hi,
>>>
>>> On Tue, May 17, 2016 at 6:59 PM, Shawn Lin
>>> <shawn.lin at kernel-upstream.org> wrote:
>>>>
>>>> Could you try this patch to see if you can still find HLE?
>>>>
>>>> @@ -2356,12 +2356,22 @@ static void dw_mci_cmd_interrupt(struct dw_mci
>>>> *host, u32 status)
>>>>   static void dw_mci_handle_cd(struct dw_mci *host)
>>>>   {
>>>>          int i;
>>>> +       int present;
>>>>
>>>>          for (i = 0; i < host->num_slots; i++) {
>>>>                  struct dw_mci_slot *slot = host->slot[i];
>>>>
>>>>                  if (!slot)
>>>>                          continue;
>>>>
>>>> +               present = !(mci_readl(slot->host, CDETECT) & (1 <<
>>>> slot->id));
>>>> +               if (present)
>>>> +                       set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>>> +               else
>>>> +                       clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>>
>>>
>>> No, because we don't use the builtin card detect on veyron.  ;)
>>>
>>> We use GPIO card detect because we didn't like the way JTAG and SD
>>> interacted.  Also on rk3288 the builtin card detect line had the wrong
>>> voltage domain (you couldn't detect a card when the IO lines were
>>> powered off).  The builtin card detect line is always driven low on
>>> veyron.
>>
>>
>> Okay, I see.
>>
>>>
>>>
>>> I'm nearly certain that the root cause of my HLE errors is actually
>>> related to the same problem addressed by the commit 7c5209c315ea
>>> ("mmc: core: Increase delay for voltage to stabilize from 3.3V to
>>> 1.8V").  I think that on minnie we're still on the hairy edge and
>>> sometimes the line doesn't transition fast enough.
>>
>>
>> Things are not so simple from your details.
>>
>> I was not enabling SD3.0 support, then I also found HLE sometimes.
>> So it seems commit 7c5209c315ea does not contibute to this phenomenon.
>
> Just to clarify, in my case commit 7c5209c315ea didn't make the
> problem worse, but made it better.  Just not better enough.  ;)
>
>
>> The scenario looks like:
>> remove sd-card -> mmc_sd_detect -> send status(CMD13) ->power_off ->
>> set_ios -> setup_bus -> disabled clk , then HLE irq storm coming
>>
>> From the code of dw_mci_prepare_command:
>> SDMMC_CMD_PRV_DAT_WAIT will not be used for CMD13, so we don't
>> wait_busy here, then cmd code is loding into queue of dw_mmc but
>> still failing send out because it's in busy?
>>
>> With my patch, things go well:
>> remove sd-card -> clear bit of DW_MMC_CARD_PRESENT  -> send
>> status(CMD13) return directly -> power_off -> set_ios -> setup_bus ->
>> disable clk
>>
>> So why should we allow inquiry of card status if we sure the card is
>> removed? I mean no any further cmds should be delivered.
>
> Quite honestly just dealing with the HLE error (my patch or
> equivalent) might be a sane solution for the problem you describe.

Yes, your patch looks good to me, so it should be merged firstly. :)
Then let's push it a bit further more that when HLEs are coming,
somethings must be wrong(currently I don't see a obvious clue from
the code itself although, I'm prone to think it belongs to the
software issue).


>
> dw_mmc needs to be able to work with an external card detect GPIO.
> It's been part of the dw_mmc driver for a long time and is (in fact)
> in use upstream at least by rk3288-veyron.  Any solution that only
> works for internal card detect is not enough.  Just handling the HLE
> error to deal with the interrupt storm and then letting Linux remove
> the card (because of the card detect interrupt) seems totally OK to
> me.
>

Sure, some of rockchip Socs use gpio for CD because they don't
have a internal CD, such as RK3036, right?

> Note: I'd be very curious if your problems get better if you disable

Not at all.

> the "grf_force_jtag" bit in the GRF.  If you're using the builtin card
> detect and you use the boot default of "grf_force_jtag" then your pins
> will be unmuxed behind your back when the card is ejected.  This could
> be causing the dw_mmc controller to get confused.

Right, grf_force_jtag is also not a friend of mine. :)
So I had disabled this function before I was debugging it.

>
>
>> And another question: should we wait busy for cmd13?
>
> I don't think so.  As I understand it CMD13 uses only the CMD line for
> communication and it should be appropriate to send this when the bus
> is "busy" (which means that the DATA lines are low).

Ahh... take back my question.. I was just considering a wired situation
that pins are unmuxed on the background(cmd line as well) when cmd13 is
delivering....


>
> Also: it seems odd that the HLE IRQ storm didn't come right after the
> CMD 13 in your description above.  Are you sure it was the CMD 13 that
> caused the HLEs, or could it has been something else?

Actually no. Any cmds be issued can trigger HLEs, I think, after sd card 
is removed When I hacked mmc_sd_detecd to send other cmds intead
of cmd13.

 From dw_mmc databook v270a(7.2.3 Clock Programming) we can see:
The DWC_mobile_storage loads each of these registers only when the
start_cmd bit and the Update_clk_regs_only bit in the CMD register are
set. When a command is successfully loaded, the DWC_mobile_storage
clears this bit, unless the DWC_mobile_storage already has another
command in the queue, at which point it gives an HLE (Hardware Locked
Error); for details on HLEs, refer to ?Error Handling? on page 233.
Software should look for the start_cmd and the Update_clk_regs_only
bits, and should also set the wait_prvdata_complete bit to ensure that
clock parameters do not change during data transfer.

Maybe the cmd is trying to load(or somethings wrong with the
controller?) when we disable the clk? That may explain my observation
that HLEs came after disabling clk.


>
>
> -Doug
>
>
>


-- 
Best Regards
Shawn Lin



From jh80.chung at samsung.com  Thu May 19 06:07:49 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Thu, 19 May 2016 22:07:49 +0900
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <10b3dc0e-aebf-664b-b36b-c54692cd9983@rock-chips.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
 <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
 <573BCC8D.5090606@kernel-upstream.org>
 <CAD=FV=VneQR3wurjezBkRhtQiH+q-FfhDN8=Ym=XqtZpVmsdUw@mail.gmail.com>
 <573C3283.1040606@rock-chips.com>
 <CAD=FV=UoT2GRYWJWXEn_ccvKGgC+PzQM_BCtLHAa7jxzbaQ9SA@mail.gmail.com>
 <10b3dc0e-aebf-664b-b36b-c54692cd9983@rock-chips.com>
Message-ID: <573DBAA5.2070706@samsung.com>

On 05/19/2016 08:31 PM, Shawn Lin wrote:
> Hi,
> 
> On 2016/5/19 1:37, Doug Anderson wrote:
>> Hi,
>>
>> On Wed, May 18, 2016 at 2:14 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>> Hi
>>>
>>>
>>> On 2016-5-18 12:12, Doug Anderson wrote:
>>>>
>>>> Hi,
>>>>
>>>> On Tue, May 17, 2016 at 6:59 PM, Shawn Lin
>>>> <shawn.lin at kernel-upstream.org> wrote:
>>>>>
>>>>> Could you try this patch to see if you can still find HLE?
>>>>>
>>>>> @@ -2356,12 +2356,22 @@ static void dw_mci_cmd_interrupt(struct dw_mci
>>>>> *host, u32 status)
>>>>>   static void dw_mci_handle_cd(struct dw_mci *host)
>>>>>   {
>>>>>          int i;
>>>>> +       int present;
>>>>>
>>>>>          for (i = 0; i < host->num_slots; i++) {
>>>>>                  struct dw_mci_slot *slot = host->slot[i];
>>>>>
>>>>>                  if (!slot)
>>>>>                          continue;
>>>>>
>>>>> +               present = !(mci_readl(slot->host, CDETECT) & (1 <<
>>>>> slot->id));
>>>>> +               if (present)
>>>>> +                       set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>>>> +               else
>>>>> +                       clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>>>
>>>>
>>>> No, because we don't use the builtin card detect on veyron.  ;)
>>>>
>>>> We use GPIO card detect because we didn't like the way JTAG and SD
>>>> interacted.  Also on rk3288 the builtin card detect line had the wrong
>>>> voltage domain (you couldn't detect a card when the IO lines were
>>>> powered off).  The builtin card detect line is always driven low on
>>>> veyron.
>>>
>>>
>>> Okay, I see.
>>>
>>>>
>>>>
>>>> I'm nearly certain that the root cause of my HLE errors is actually
>>>> related to the same problem addressed by the commit 7c5209c315ea
>>>> ("mmc: core: Increase delay for voltage to stabilize from 3.3V to
>>>> 1.8V").  I think that on minnie we're still on the hairy edge and
>>>> sometimes the line doesn't transition fast enough.
>>>
>>>
>>> Things are not so simple from your details.
>>>
>>> I was not enabling SD3.0 support, then I also found HLE sometimes.
>>> So it seems commit 7c5209c315ea does not contibute to this phenomenon.
>>
>> Just to clarify, in my case commit 7c5209c315ea didn't make the
>> problem worse, but made it better.  Just not better enough.  ;)
>>
>>
>>> The scenario looks like:
>>> remove sd-card -> mmc_sd_detect -> send status(CMD13) ->power_off ->
>>> set_ios -> setup_bus -> disabled clk , then HLE irq storm coming
>>>
>>> From the code of dw_mci_prepare_command:
>>> SDMMC_CMD_PRV_DAT_WAIT will not be used for CMD13, so we don't
>>> wait_busy here, then cmd code is loding into queue of dw_mmc but
>>> still failing send out because it's in busy?
>>>
>>> With my patch, things go well:
>>> remove sd-card -> clear bit of DW_MMC_CARD_PRESENT  -> send
>>> status(CMD13) return directly -> power_off -> set_ios -> setup_bus ->
>>> disable clk
>>>
>>> So why should we allow inquiry of card status if we sure the card is
>>> removed? I mean no any further cmds should be delivered.
>>
>> Quite honestly just dealing with the HLE error (my patch or
>> equivalent) might be a sane solution for the problem you describe.
> 
> Yes, your patch looks good to me, so it should be merged firstly. :)
> Then let's push it a bit further more that when HLEs are coming,
> somethings must be wrong(currently I don't see a obvious clue from
> the code itself although, I'm prone to think it belongs to the
> software issue).

We don't know what's main cause for HLE..But i also think it's relevant to SW issue.
But we need to consider all possibilities..

> 
> 
>>
>> dw_mmc needs to be able to work with an external card detect GPIO.
>> It's been part of the dw_mmc driver for a long time and is (in fact)
>> in use upstream at least by rk3288-veyron.  Any solution that only
>> works for internal card detect is not enough.  Just handling the HLE
>> error to deal with the interrupt storm and then letting Linux remove
>> the card (because of the card detect interrupt) seems totally OK to
>> me.
>>
> 
> Sure, some of rockchip Socs use gpio for CD because they don't
> have a internal CD, such as RK3036, right?
> 
>> Note: I'd be very curious if your problems get better if you disable
> 
> Not at all.
> 
>> the "grf_force_jtag" bit in the GRF.  If you're using the builtin card
>> detect and you use the boot default of "grf_force_jtag" then your pins
>> will be unmuxed behind your back when the card is ejected.  This could
>> be causing the dw_mmc controller to get confused.
> 
> Right, grf_force_jtag is also not a friend of mine. :)
> So I had disabled this function before I was debugging it.
> 
>>
>>
>>> And another question: should we wait busy for cmd13?
>>
>> I don't think so.  As I understand it CMD13 uses only the CMD line for
>> communication and it should be appropriate to send this when the bus
>> is "busy" (which means that the DATA lines are low).
> 
> Ahh... take back my question.. I was just considering a wired situation
> that pins are unmuxed on the background(cmd line as well) when cmd13 is
> delivering....
> 
> 
>>
>> Also: it seems odd that the HLE IRQ storm didn't come right after the
>> CMD 13 in your description above.  Are you sure it was the CMD 13 that
>> caused the HLEs, or could it has been something else?
> 
> Actually no. Any cmds be issued can trigger HLEs, I think, after sd card is removed When I hacked mmc_sd_detecd to send other cmds intead
> of cmd13.
> 
> From dw_mmc databook v270a(7.2.3 Clock Programming) we can see:
> The DWC_mobile_storage loads each of these registers only when the
> start_cmd bit and the Update_clk_regs_only bit in the CMD register are
> set. When a command is successfully loaded, the DWC_mobile_storage
> clears this bit, unless the DWC_mobile_storage already has another
> command in the queue, at which point it gives an HLE (Hardware Locked
> Error); for details on HLEs, refer to ?Error Handling? on page 233.
> Software should look for the start_cmd and the Update_clk_regs_only
> bits, and should also set the wait_prvdata_complete bit to ensure that
> clock parameters do not change during data transfer.
> 
> Maybe the cmd is trying to load(or somethings wrong with the
> controller?) when we disable the clk? That may explain my observation
> that HLEs came after disabling clk.

I agreed.

To Disable clock, it sends cmd with update_clk_regs_only and wait_prvdata_complete bit.
I think it's problem..(waiting for prvdata..)

If there are ongoing some data(read/write), then before disabling clock, waiting for completing previous data.
(But card was already removed, and it couldn't do anything.)
It's difficult to analyze the HLE..So After applying first, then we can solve this problem, step by step.

Best Regards,
Jaehoon Chung

> 
> 
>>
>>
>> -Doug
>>
>>
>>
> 
> 



From wxt at rock-chips.com  Thu May 19 08:47:02 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Thu, 19 May 2016 23:47:02 +0800
Subject: [PATCH 1/3] spi/rockchip: add rk3036/rk3228/rk3368 socs for spi
 document
Message-ID: <1463672824-15367-1-git-send-email-wxt@rock-chips.com>

We had supported the rk3036/rk3066/rk3188/rk3228/rk3288/rk3368/rk3399
family SoCs in linux kernel.

Let's add the other SoCs, in order to a better understanding from the
rockchip spi document.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Rob Herring <robh+dt at kernel.org>
Cc: Mark Brown <broonie at kernel.org>
Cc: Heiko Stuebner <heiko at sntech.de>
Cc: linux-rockchip at lists.infradead.org
---

 Documentation/devicetree/bindings/spi/spi-rockchip.txt | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
index 1b14d69..305b542 100644
--- a/Documentation/devicetree/bindings/spi/spi-rockchip.txt
+++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
@@ -6,9 +6,12 @@ and display controllers using the SPI communication interface.
 Required Properties:
 
 - compatible: should be one of the following.
+    "rockchip,rk3036-spi" for rk3036.
     "rockchip,rk3066-spi" for rk3066.
     "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188.
+    "rockchip,rk3228-spi", "rockchip,rk3066-spi" for rk3228.
     "rockchip,rk3288-spi", "rockchip,rk3066-spi" for rk3288.
+    "rockchip,rk3368-spi", "rockchip,rk3066-spi" for rk3368.
     "rockchip,rk3399-spi", "rockchip,rk3066-spi" for rk3399.
 - reg: physical base address of the controller and length of memory mapped
        region.
-- 
2.7.4



From wxt at rock-chips.com  Thu May 19 08:47:03 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Thu, 19 May 2016 23:47:03 +0800
Subject: [PATCH 2/3] spi/rockchip: add the rk3036/rk3228/rk3368 to match for
 driver
In-Reply-To: <1463672824-15367-1-git-send-email-wxt@rock-chips.com>
References: <1463672824-15367-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1463672824-15367-2-git-send-email-wxt@rock-chips.com>

In gerenal, the "rockchip,rockchip-spi" string will match the dts
that's great in spi driver. After all the most of rockchip SoCs ar
same spi controller.

Then, we should keep the old style to match the dts various.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Mark Brown <broonie at kernel.org>
Cc: Heiko Stuebner <heiko at sntech.de>
Cc: linux-rockchip at lists.infradead.org
---

 drivers/spi/spi-rockchip.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 6c6c001..dd08b68 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -893,9 +893,12 @@ static const struct dev_pm_ops rockchip_spi_pm = {
 };
 
 static const struct of_device_id rockchip_spi_dt_match[] = {
+	{ .compatible = "rockchip,rk3036-spi", },
 	{ .compatible = "rockchip,rk3066-spi", },
 	{ .compatible = "rockchip,rk3188-spi", },
+	{ .compatible = "rockchip,rk3228-spi", },
 	{ .compatible = "rockchip,rk3288-spi", },
+	{ .compatible = "rockchip,rk3368-spi", },
 	{ .compatible = "rockchip,rk3399-spi", },
 	{ },
 };
-- 
2.7.4



From wxt at rock-chips.com  Thu May 19 08:47:04 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Thu, 19 May 2016 23:47:04 +0800
Subject: [PATCH 3/3] ARM: dts: rockchip: fixes the spi compatible for rk3036
In-Reply-To: <1463672824-15367-1-git-send-email-wxt@rock-chips.com>
References: <1463672824-15367-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1463672824-15367-3-git-send-email-wxt@rock-chips.com>

That's seem the incorrect string to match the spi driver.

Fixes commit f629fcfab2cd
("ARM: dts: rockchip: support the spi for rk3036")

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Heiko Stuebner <heiko at sntech.de>
Cc: linux-rockchip at lists.infradead.org

---

 arch/arm/boot/dts/rk3036.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi
index d0f4bb7..a30700a 100644
--- a/arch/arm/boot/dts/rk3036.dtsi
+++ b/arch/arm/boot/dts/rk3036.dtsi
@@ -431,7 +431,7 @@
 	};
 
 	spi: spi at 20074000 {
-		compatible = "rockchip,rockchip-spi";
+		compatible = "rockchip,rk3036-spi";
 		reg = <0x20074000 0x1000>;
 		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
 		clocks =<&cru PCLK_SPI>, <&cru SCLK_SPI>;
-- 
2.7.4



From heiko at sntech.de  Thu May 19 08:51:54 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Thu, 19 May 2016 17:51:54 +0200
Subject: [PATCH 1/3] spi/rockchip: add rk3036/rk3228/rk3368 socs for spi
 document
In-Reply-To: <1463672824-15367-1-git-send-email-wxt@rock-chips.com>
References: <1463672824-15367-1-git-send-email-wxt@rock-chips.com>
Message-ID: <3685935.dKdIbE8hXb@phil>

Am Donnerstag, 19. Mai 2016, 23:47:02 schrieb Caesar Wang:
> We had supported the rk3036/rk3066/rk3188/rk3228/rk3288/rk3368/rk3399
> family SoCs in linux kernel.
> 
> Let's add the other SoCs, in order to a better understanding from the
> rockchip spi document.
> 
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Rob Herring <robh+dt at kernel.org>
> Cc: Mark Brown <broonie at kernel.org>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Cc: linux-rockchip at lists.infradead.org
> ---
> 
>  Documentation/devicetree/bindings/spi/spi-rockchip.txt | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt
> b/Documentation/devicetree/bindings/spi/spi-rockchip.txt index
> 1b14d69..305b542 100644
> --- a/Documentation/devicetree/bindings/spi/spi-rockchip.txt
> +++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
> @@ -6,9 +6,12 @@ and display controllers using the SPI communication
> interface. Required Properties:
> 
>  - compatible: should be one of the following.
> +    "rockchip,rk3036-spi" for rk3036.

shouldn't the rk3036 also get the rk3066 fallback. Looking at the driver 
part (patch2) the rk3036 still is the same IP as for every other soc in 
here.

>      "rockchip,rk3066-spi" for rk3066.
>      "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188.
> +    "rockchip,rk3228-spi", "rockchip,rk3066-spi" for rk3228.
>      "rockchip,rk3288-spi", "rockchip,rk3066-spi" for rk3288.
> +    "rockchip,rk3368-spi", "rockchip,rk3066-spi" for rk3368.
>      "rockchip,rk3399-spi", "rockchip,rk3066-spi" for rk3399.
>  - reg: physical base address of the controller and length of memory
> mapped region.



From wxt at rock-chips.com  Thu May 19 09:04:07 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 20 May 2016 00:04:07 +0800
Subject: [PATCH 1/3] spi/rockchip: add rk3036/rk3228/rk3368 socs for spi
 document
In-Reply-To: <3685935.dKdIbE8hXb@phil>
References: <1463672824-15367-1-git-send-email-wxt@rock-chips.com>
 <3685935.dKdIbE8hXb@phil>
Message-ID: <573DE3F7.6070300@rock-chips.com>



? 2016?05?19? 23:51, Heiko Stuebner ??:
> Am Donnerstag, 19. Mai 2016, 23:47:02 schrieb Caesar Wang:
>> We had supported the rk3036/rk3066/rk3188/rk3228/rk3288/rk3368/rk3399
>> family SoCs in linux kernel.
>>
>> Let's add the other SoCs, in order to a better understanding from the
>> rockchip spi document.
>>
>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>> Cc: Rob Herring <robh+dt at kernel.org>
>> Cc: Mark Brown <broonie at kernel.org>
>> Cc: Heiko Stuebner <heiko at sntech.de>
>> Cc: linux-rockchip at lists.infradead.org
>> ---
>>
>>   Documentation/devicetree/bindings/spi/spi-rockchip.txt | 3 +++
>>   1 file changed, 3 insertions(+)
>>
>> diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt
>> b/Documentation/devicetree/bindings/spi/spi-rockchip.txt index
>> 1b14d69..305b542 100644
>> --- a/Documentation/devicetree/bindings/spi/spi-rockchip.txt
>> +++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
>> @@ -6,9 +6,12 @@ and display controllers using the SPI communication
>> interface. Required Properties:
>>
>>   - compatible: should be one of the following.
>> +    "rockchip,rk3036-spi" for rk3036.
> shouldn't the rk3036 also get the rk3066 fallback. Looking at the driver
> part (patch2) the rk3036 still is the same IP as for every other soc in
> here.

Yep, the same IP.

Do you think we should keep the below style?

1)
"rockchip,rk3036-spi", "rockchip,rk3066-spi" for rk3036.
  "rockchip,rk3066-spi" for rk3066.
  "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188.
...

or
2)
  "rockchip,rk3066-spi" for rk3066.
"rockchip,rk3036-spi", "rockchip,rk3066-spi" for rk3036.
  "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188
..

or
3)
"rockchip, rockchip-spi" for rk3036 rk3066.......

Think about the 1) will be googd select.

-Caesar

>>       "rockchip,rk3066-spi" for rk3066.
>>       "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188.
>> +    "rockchip,rk3228-spi", "rockchip,rk3066-spi" for rk3228.
>>       "rockchip,rk3288-spi", "rockchip,rk3066-spi" for rk3288.
>> +    "rockchip,rk3368-spi", "rockchip,rk3066-spi" for rk3368.
>>       "rockchip,rk3399-spi", "rockchip,rk3066-spi" for rk3399.
>>   - reg: physical base address of the controller and length of memory
>> mapped region.
>
>
>




From heiko at sntech.de  Thu May 19 09:20:58 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Thu, 19 May 2016 18:20:58 +0200
Subject: [PATCH 1/3] spi/rockchip: add rk3036/rk3228/rk3368 socs for spi
 document
In-Reply-To: <573DE3F7.6070300@rock-chips.com>
References: <1463672824-15367-1-git-send-email-wxt@rock-chips.com>
 <3685935.dKdIbE8hXb@phil> <573DE3F7.6070300@rock-chips.com>
Message-ID: <3828505.WBLtTjjB7h@phil>

Am Freitag, 20. Mai 2016, 00:04:07 schrieb Caesar Wang:
> ? 2016?05?19? 23:51, Heiko Stuebner ??:
> > Am Donnerstag, 19. Mai 2016, 23:47:02 schrieb Caesar Wang:
> >> We had supported the rk3036/rk3066/rk3188/rk3228/rk3288/rk3368/rk3399
> >> family SoCs in linux kernel.
> >> 
> >> Let's add the other SoCs, in order to a better understanding from the
> >> rockchip spi document.
> >> 
> >> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> >> Cc: Rob Herring <robh+dt at kernel.org>
> >> Cc: Mark Brown <broonie at kernel.org>
> >> Cc: Heiko Stuebner <heiko at sntech.de>
> >> Cc: linux-rockchip at lists.infradead.org
> >> ---
> >> 
> >>   Documentation/devicetree/bindings/spi/spi-rockchip.txt | 3 +++
> >>   1 file changed, 3 insertions(+)
> >> 
> >> diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt
> >> b/Documentation/devicetree/bindings/spi/spi-rockchip.txt index
> >> 1b14d69..305b542 100644
> >> --- a/Documentation/devicetree/bindings/spi/spi-rockchip.txt
> >> +++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
> >> @@ -6,9 +6,12 @@ and display controllers using the SPI communication
> >> 
> >> interface. Required Properties:
> >>   - compatible: should be one of the following.
> >> 
> >> +    "rockchip,rk3036-spi" for rk3036.
> > 
> > shouldn't the rk3036 also get the rk3066 fallback. Looking at the driver
> > part (patch2) the rk3036 still is the same IP as for every other soc in
> > here.
> 
> Yep, the same IP.
> 
> Do you think we should keep the below style?
> 
> 1)
> "rockchip,rk3036-spi", "rockchip,rk3066-spi" for rk3036.
>   "rockchip,rk3066-spi" for rk3066.
>   "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188.
> ...
> 
> or
> 2)
>   "rockchip,rk3066-spi" for rk3066.
> "rockchip,rk3036-spi", "rockchip,rk3066-spi" for rk3036.
>   "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188
> ..
> 
> or
> 3)
> "rockchip, rockchip-spi" for rk3036 rk3066.......
> 
> Think about the 1) will be googd select.

or
(4) drop the fallbacks. We match against each compatible all the time 
anyway, so you could also simply do

  "rockchip,rk3036-spi" for rk3036
  "rockchip,rk3066-spi" for rk3066
  "rockchip,rk3188-spi" for rk3188

Maybe leave the fallbacks for existing socs, and just add the new ones 
without the fallbacks.

rockchip,rockchip-spi is not future proof ... i.e. in some future soc 
somebody might want to exchange the IP block against a different one, so 
being specific saves us from hassle then :-)


Heiko

> >>       "rockchip,rk3066-spi" for rk3066.
> >>       "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188.
> >> 
> >> +    "rockchip,rk3228-spi", "rockchip,rk3066-spi" for rk3228.
> >> 
> >>       "rockchip,rk3288-spi", "rockchip,rk3066-spi" for rk3288.
> >> 
> >> +    "rockchip,rk3368-spi", "rockchip,rk3066-spi" for rk3368.
> >> 
> >>       "rockchip,rk3399-spi", "rockchip,rk3066-spi" for rk3399.
> >>   
> >>   - reg: physical base address of the controller and length of memory
> >> 
> >> mapped region.



From eballetbo at gmail.com  Thu May 19 09:53:09 2016
From: eballetbo at gmail.com (Enric Balletbo Serra)
Date: Thu, 19 May 2016 18:53:09 +0200
Subject: [PATCH v3] mmc: dw_mmc: rockchip: Set the drive phase properly
In-Reply-To: <2865073.LogD6IIKLp@phil>
References: <1463077910-25914-1-git-send-email-dianders@chromium.org>
 <2865073.LogD6IIKLp@phil>
Message-ID: <CAFqH_52KqPXM_AjC8qKrVvH2hSvqtiBjmN28SZgJgoWVCe0pmg@mail.gmail.com>

2016-05-13 0:52 GMT+02:00 Heiko Stuebner <heiko at sntech.de>:
> Am Donnerstag, 12. Mai 2016, 11:31:50 schrieb Douglas Anderson:
>
> [...]
>
>> In commit 7a03fe6f48f3 ("clk: rockchip: reset init state before mmc card
>> initialization") we actually started setting this explicitly in the
>> kernel, but that commit wasn't quite right and also wasn't quite
>> enough.  See <https://patchwork.kernel.org/patch/9085311/> for some
>> details.
>>
>> Let's explicitly set this phase in dw_mmc.
>
> [...]
>
>> Fixes: 7a03fe6f48f3 ("clk: rockchip: reset init state before mmc card
>> initialization") Signed-off-by: Douglas Anderson <dianders at chromium.org>
>> Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>
>
> I've tested this patch together with the two clock patches linked above on a
> rk3288-firefly and a rk3288-veyron-jerry. On the firefly tuning still does not
> work (probably really some regulator issue) and on veyron tuning still works
> as expected, so
>
> Tested-by: Heiko Stuebner <heiko at sntech.de>
>
> Doug's explanations both in the commit message and the code look sane to me,
> but I don't feel confident enough in my understanding of the matter to
> transform that into a Reviewed-by tag.
>
>

I've tested this patch on rock2 square inserting some uSD cards and
seeing that they still enumerate properly, also I booted from a uSD
card.
Note that in current state UHS is not supported so the tuning is not
executed. Enable UHS on rock2 requires some work, I'll try to look at
it but meanwhile I can say that doesn't break current state, so

Tested-by: Enric Balletbo i Serra <enric.balletbo at collabora.com>

> Heiko
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html


From LinoSanfilippo at gmx.de  Thu May 19 14:15:56 2016
From: LinoSanfilippo at gmx.de (Lino Sanfilippo)
Date: Thu, 19 May 2016 23:15:56 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160518225529.GA18671@electric-eye.fr.zoreil.com>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com> <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com>
Message-ID: <573E2D0C.604@gmx.de>

Hi Francois,

On 19.05.2016 00:55, Francois Romieu wrote:

>> The smp_wmb() in tx function combined with the smp_rmb() in tx_clean ensures
>> that the CPU running tx_clean sees consistent values for info, data and skb 
>> (thus no need to check for validity of all three values any more).
>> The mb() fulfills several tasks:
>> 1. makes sure that DMA writes to descriptor are completed before the HW is
>>     informed.
> 
> "DMA writes" == "CPU writes" ?
> 

I admit that phrasing was unfortunate. What I meant was, that we have to make sure that
the writes to the descriptors which reside in DMA memory have to be completed before
we inform the hardware. This is since the write to the mmio (arc_reg_set(R_STATUS, TXPL_MASK))
may otherwise overtake the writes to the desriptors in DMA and thus the hardware find an
incompletely set up descriptor.
You can find a barrier for this reason in quite a lot drivers. Normally a dma_rmb() would
be sufficient for this, e.g here

http://lxr.free-electrons.com/source/drivers/net/ethernet/marvell/sky2.c#L1139

or here

http://lxr.free-electrons.com/source/drivers/net/ethernet/intel/ixgb/ixgb_main.c#L1468

but we have to use the mb() instead, because we also have to solve issues 2. and 3.:

2. requires a smp_wmb, while 3. requires a rmb(). AFAIK the mb() implies all we need, 
the dma_rmb() for 1., the smp_wmb() for 2. and the rmb() for 3. 

>> 2. On multi processor systems: ensures that txbd_curr is updated (this is paired
>>     with the smp_mb() at the end of tx_clean).
> 
> Smells like using barrier side-effects to control smp coherency. It isn't
> the recommended style.
> 

As I wrote above, the mb() implies the smp_wmb() so this is a regular pairing
of smp_wmb() in xmit and smb_mb() in tx_clean, nothing uncommon.

>> -		if ((info & FOR_EMAC) || !txbd->data || !skb)
>> +		if (info & FOR_EMAC) {
>> +			/* Make sure we see consistent values for info, skb
>> +			 * and data.
>> +			 */
>> +			smp_rmb();
>>  			break;
>> +		}
> 
> ?
> 
> smp_rmb should appear before the variables you want coherency for.

I dont think so. Please take a look into the memory barriers documentation.
There is an example that is pretty close to the situation that we have in this driver:

http://lxr.free-electrons.com/source/Documentation/memory-barriers.txt#L1819

In that example the barrier is also _between_ the variables that are to be ordered, not 
before. 
Also in the example a dma_rmb() is sufficient, because in the sample code only reads to DMA
memory have to be ordered. In our case we want to order between DMA (info) and RAM ("data" and the skb).
However smp barriers are not sufficient (as I used it in the former patch), since we do not only
want to sync CPU-CPU but also CPU-DMA. Please see the new patch I attached in which mandatory 
barriers are used instead. 


>> -	skb_tx_timestamp(skb);
>> +	/* Make sure info is set after data and skb with respect to
>> +	 * other tx_clean().
>> +	 */
>> +	smp_wmb();
>>  
>>  	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
> 
> Afaik smp_wmb() does not imply wmb(). So priv->txbd[*txbd_curr].data and
> *info (aka priv->txbd[*txbd_curr].info) are not necessarily written in
> an orderly manner.

Right, as I already wrote above I changed the smp barriers to mandatory ones.

> 
>>  
>> -	/* Make sure info word is set */
>> -	wmb();
>> -
>> -	priv->tx_buff[*txbd_curr].skb = skb;
>> -
>>  	/* Increment index to point to the next BD */
>>  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
> 
> With this change it's possible that tx_clean() reads new value for
> tx_curr and old value (0) for *info.

Even if this could happen, what is the problem? I cant see an issue
that results from such a scenario.

>>  	 * of the queue in tx_clean().
>> +	 * 2.Ensure that all values are written to RAM and to DMA
>> +	 * before hardware is informed.
> 
> (I am not sure what "DMA" is supposed to mean here.)
> 

This is about the DMA/mmio race I described above.

>> +	 * 3.Ensure we see the most recent value for tx_dirty.
>>  	 */
>> -	smp_mb();
>> +	mb();
>>  
>> -	if (!arc_emac_tx_avail(priv)) {
>> +	if (!arc_emac_tx_avail(priv))
>>  		netif_stop_queue(ndev);
>> -		/* Refresh tx_dirty */
>> -		smp_mb();
>> -		if (arc_emac_tx_avail(priv))
>> -			netif_start_queue(ndev);
>> -	}
> 
> Xmit thread                        | Clean thread
> 
> mb();
> 
> arc_emac_tx_avail() test with old
> tx_dirty - tx_clean has not issued
> any mb yet - and new tx_curr
> 
>                                      smp_mb();
> 
>                                      if (netif_queue_stopped(ndev) && ...
>                                              netif_wake_queue(ndev);
> 
> netif_stop_queue()
> 
> -> queue stopped.
> 

Again, the mb() we have now implies the smb_mb() we had before. So nothing changed
except that we can be sure to see the new value for tx_dirty at our first attempt.

>> +
>> +	skb_tx_timestamp(skb);
> 
> You don't want to issue skb_tx_timestamp after releasing control of the
> descriptor (*info = ...): skb may be long gone.
> 

Youre right, I replaced the call to skb_tx_timestamp so that should be ok now, too.
New patch is below. 

Regards,
Lino

---
 drivers/net/ethernet/arc/emac_main.c | 33 +++++++++++++++++----------------
 1 file changed, 17 insertions(+), 16 deletions(-)

diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index a3a9392..b986499 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -162,8 +162,13 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 		struct sk_buff *skb = tx_buff->skb;
 		unsigned int info = le32_to_cpu(txbd->info);
 
-		if ((info & FOR_EMAC) || !txbd->data || !skb)
+		if (info & FOR_EMAC) {
+			/* Make sure we see consistent values for info, skb
+			 * and data.
+			 */
+			rmb();
 			break;
+		}
 
 		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
 			stats->tx_errors++;
@@ -680,35 +685,31 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
 	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
 
 	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
-
-	/* Make sure pointer to data buffer is set */
-	wmb();
+	priv->tx_buff[*txbd_curr].skb = skb;
 
 	skb_tx_timestamp(skb);
 
-	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
-
-	/* Make sure info word is set */
+	/* Make sure info is set after data and skb with respect to
+	 * tx_clean().
+	 */
 	wmb();
 
-	priv->tx_buff[*txbd_curr].skb = skb;
+	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
 	/* Increment index to point to the next BD */
 	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
 
-	/* Ensure that tx_clean() sees the new txbd_curr before
+	/* 1.Ensure that tx_clean() sees the new txbd_curr before
 	 * checking the queue status. This prevents an unneeded wake
 	 * of the queue in tx_clean().
+	 * 2.Ensure that all values are written to RAM and to DMA
+	 * before hardware is informed.
+	 * 3.Ensure we see the most recent value for tx_dirty.
 	 */
-	smp_mb();
+	mb();
 
-	if (!arc_emac_tx_avail(priv)) {
+	if (!arc_emac_tx_avail(priv))
 		netif_stop_queue(ndev);
-		/* Refresh tx_dirty */
-		smp_mb();
-		if (arc_emac_tx_avail(priv))
-			netif_start_queue(ndev);
-	}
 
 	arc_reg_set(priv, R_STATUS, TXPL_MASK);




From wxt at rock-chips.com  Thu May 19 16:56:20 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 20 May 2016 07:56:20 +0800
Subject: [PATCH v2 1/3] spi/rockchip: add rk3036/rk3228/rk3368 SoCs for spi
 document
Message-ID: <1463702182-5188-1-git-send-email-wxt@rock-chips.com>

We had supported the rk3036/rk3066/rk3188/rk3228/rk3288/rk3368/rk3399
family SoCs in linux kernel.

Let's add the other SoCs, in order to a better understanding from the
rockchip spi document.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Rob Herring <robh+dt at kernel.org>
Cc: Mark Brown <broonie at kernel.org>
Cc: Heiko Stuebner <heiko at sntech.de>
Cc: linux-rockchip at lists.infradead.org

---

Changes in v2:
- Drop the fallbacks, As Heiko comments on https://patchwork.kernel.org/patch/9127881/
- update commit

 Documentation/devicetree/bindings/spi/spi-rockchip.txt | 11 +++++++----
 1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/Documentation/devicetree/bindings/spi/spi-rockchip.txt b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
index 1b14d69..d2ca153 100644
--- a/Documentation/devicetree/bindings/spi/spi-rockchip.txt
+++ b/Documentation/devicetree/bindings/spi/spi-rockchip.txt
@@ -6,10 +6,13 @@ and display controllers using the SPI communication interface.
 Required Properties:
 
 - compatible: should be one of the following.
-    "rockchip,rk3066-spi" for rk3066.
-    "rockchip,rk3188-spi", "rockchip,rk3066-spi" for rk3188.
-    "rockchip,rk3288-spi", "rockchip,rk3066-spi" for rk3288.
-    "rockchip,rk3399-spi", "rockchip,rk3066-spi" for rk3399.
+    "rockchip,rk3036-spi" for rk3036 SoCS.
+    "rockchip,rk3066-spi" for rk3066 SoCs.
+    "rockchip,rk3188-spi" for rk3188 SoCs.
+    "rockchip,rk3228-spi" for rk3228 SoCS.
+    "rockchip,rk3288-spi" for rk3288 SoCs.
+    "rockchip,rk3368-spi" for rk3368 SoCs.
+    "rockchip,rk3399-spi" for rk3399 SoCs.
 - reg: physical base address of the controller and length of memory mapped
        region.
 - interrupts: The interrupt number to the cpu. The interrupt specifier format
-- 
2.7.4



From wxt at rock-chips.com  Thu May 19 16:56:21 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 20 May 2016 07:56:21 +0800
Subject: [PATCH v2 2/3] spi/rockchip: add the rk3036/rk3228/rk3368 to match
 for driver
In-Reply-To: <1463702182-5188-1-git-send-email-wxt@rock-chips.com>
References: <1463702182-5188-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1463702182-5188-2-git-send-email-wxt@rock-chips.com>

In gerenal, the "rockchip,rockchip-spi" string will match the dts
that's great in spi driver. After all the most of rockchip SoCs ar
same spi controller.

Then, we should keep the old style to match the dts various.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Mark Brown <broonie at kernel.org>
Cc: Heiko Stuebner <heiko at sntech.de>
Cc: linux-rockchip at lists.infradead.org
---

Changes in v2: None

 drivers/spi/spi-rockchip.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 6c6c001..dd08b68 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -893,9 +893,12 @@ static const struct dev_pm_ops rockchip_spi_pm = {
 };
 
 static const struct of_device_id rockchip_spi_dt_match[] = {
+	{ .compatible = "rockchip,rk3036-spi", },
 	{ .compatible = "rockchip,rk3066-spi", },
 	{ .compatible = "rockchip,rk3188-spi", },
+	{ .compatible = "rockchip,rk3228-spi", },
 	{ .compatible = "rockchip,rk3288-spi", },
+	{ .compatible = "rockchip,rk3368-spi", },
 	{ .compatible = "rockchip,rk3399-spi", },
 	{ },
 };
-- 
2.7.4



From wxt at rock-chips.com  Thu May 19 16:56:22 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 20 May 2016 07:56:22 +0800
Subject: [PATCH v2 3/3] ARM: dts: rockchip: fixes the spi compatible for rk3036
In-Reply-To: <1463702182-5188-1-git-send-email-wxt@rock-chips.com>
References: <1463702182-5188-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1463702182-5188-3-git-send-email-wxt@rock-chips.com>

That's seem the incorrect string to match the spi driver.

Fixes commit f629fcfab2cd
("ARM: dts: rockchip: support the spi for rk3036")

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Heiko Stuebner <heiko at sntech.de>
Cc: linux-rockchip at lists.infradead.org

---

Changes in v2: None

 arch/arm/boot/dts/rk3036.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi
index d0f4bb7..a30700a 100644
--- a/arch/arm/boot/dts/rk3036.dtsi
+++ b/arch/arm/boot/dts/rk3036.dtsi
@@ -431,7 +431,7 @@
 	};
 
 	spi: spi at 20074000 {
-		compatible = "rockchip,rockchip-spi";
+		compatible = "rockchip,rk3036-spi";
 		reg = <0x20074000 0x1000>;
 		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
 		clocks =<&cru PCLK_SPI>, <&cru SCLK_SPI>;
-- 
2.7.4



From dianders at chromium.org  Thu May 19 17:11:40 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 19 May 2016 17:11:40 -0700
Subject: [PATCH v3 5/5] mmc: sdhci-of-arasan: implement enhanced strobe
 callback
In-Reply-To: <1462871407-32566-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
 <1462871407-32566-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAD=FV=VU7cY+jQ3Tys5vLY_=pP-w5-cKxNTs5JBRxkwr+nVjmQ@mail.gmail.com>

Hi,

On Tue, May 10, 2016 at 2:10 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> Currently sdhci-arasan 5.1 can support enhanced strobe function,
> and we now limit it just for "arasan,sdhci-5.1". Add
> mmc-hs400-enhanced-strobe in DT to enable the function if we'r sure

nit:s/we'r/we're/

[ ... ]
> @@ -79,6 +81,21 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
>         }
>  }
>
> +static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
> +                                       struct mmc_ios *ios)
> +{
> +       u32 vendor;
> +       struct sdhci_host *host = mmc_priv(mmc);
> +
> +       vendor = readl(host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
> +       if (ios->enhanced_strobe)
> +               vendor |= VENDOR_ENHANCED_STROBE;
> +       else
> +               vendor &= (~VENDOR_ENHANCED_STROBE);

nit: no extra parentheses:

  vendor &= ~VENDOR_ENHANCED_STROBE;


Other than the nits this patch looks good to me.  Feel free to add my
Reviewed-by when nits fixed.

-Doug


From dianders at chromium.org  Thu May 19 17:18:10 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 19 May 2016 17:18:10 -0700
Subject: [PATCH v3 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <1462871391-32484-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
 <1462871391-32484-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAD=FV=Xv-c2owh+dDT1EJYPrKsahxOoQUhJiZFprtk4FxHAK1A@mail.gmail.com>

Hi,

On Tue, May 10, 2016 at 2:09 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> Controllers use data strobe line to latch data from devices
> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
> introduces enhanced strobe mode for latching cmd response from
> emmc devices to host controllers. This new feature is optional,
> so it depends both on device's cap and host's cap to decide
> whether to use it or not.

I don't totally understand it, but two boards I'm working with have
eMMC devices that claim to be eMMC 5.0 devices but also have support
for strobe.  Did people just cherry-pick this feature from eMMC 5.1 to
their eMMC 5.0 devices?


> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
>
> Changes in v3: None
> Changes in v2: None
>
>  drivers/mmc/core/bus.c   |  3 +-
>  drivers/mmc/core/core.c  |  8 +++++
>  drivers/mmc/core/mmc.c   | 79 ++++++++++++++++++++++++++++++++++++++++++++++--
>  include/linux/mmc/card.h |  1 +
>  include/linux/mmc/host.h | 11 +++++++
>  include/linux/mmc/mmc.h  |  3 ++
>  6 files changed, 102 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index 4bc48f1..7e94b9d 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>                         mmc_card_ddr52(card) ? "DDR " : "",
>                         type);
>         } else {
> -               pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> +               pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>                         mmc_hostname(card->host),
>                         mmc_card_uhs(card) ? "ultra high speed " :
>                         (mmc_card_hs(card) ? "high speed " : ""),
>                         mmc_card_hs400(card) ? "HS400 " :
>                         (mmc_card_hs200(card) ? "HS200 " : ""),
> +                       mmc_card_hs400es(card) ? "Enhanced strobe" : "",

Nit: there should be a space before the quote.  Otherwise the message
runs together, like:

new HS400 Enhanced strobeMMC card at address 0001


>                         mmc_card_ddr52(card) ? "DDR " : "",
>                         uhs_bus_speed_mode, type, card->rca);
>         }
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 99275e4..a559501 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -1127,6 +1127,14 @@ void mmc_set_initial_state(struct mmc_host *host)
>         host->ios.bus_width = MMC_BUS_WIDTH_1;
>         host->ios.timing = MMC_TIMING_LEGACY;
>         host->ios.drv_type = 0;
> +       host->ios.enhanced_strobe = false;
> +
> +       /*
> +        * Make sure we are in non-enhanced strobe mode before we
> +        * actually enable it in ext_csd.
> +        */
> +       if (host->ops->hs400_enhanced_strobe)
> +               host->ops->hs400_enhanced_strobe(host, &host->ios);
>
>         mmc_set_ios(host);
>  }
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index f99c47e..c2d1981 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>                 avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>         }
>
> +       if ((caps2 & MMC_CAP2_HS400_ES) &&
> +           card->ext_csd.strobe_support &&
> +           (card_type & EXT_CSD_CARD_TYPE_HS400))
> +               avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
> +
>         card->ext_csd.hs_max_dtr = hs_max_dtr;
>         card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>         card->mmc_avail_type = avail_type;
> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>                         mmc_card_set_blockaddr(card);
>         }
>
> +       card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>         card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>         mmc_select_card_type(card);
>
> @@ -1216,6 +1222,73 @@ out_err:
>         return err;
>  }
>
> +static int mmc_select_hs400es(struct mmc_card *card)
> +{
> +       struct mmc_host *host = card->host;
> +       int err = 0;
> +       u8 val;
> +
> +       err = mmc_select_bus_width(card);
> +       if (IS_ERR_VALUE(err))
> +               goto out_err;
> +
> +       /* Switch card to HS mode */
> +       err = mmc_select_hs(card);
> +       if (err) {
> +               pr_err("%s: switch to high-speed failed, err:%d\n",
> +                       mmc_hostname(host), err);
> +               goto out_err;
> +       }
> +
> +       err = mmc_switch_status(card);
> +       if (err)
> +               goto out_err;
> +
> +       /* Switch card to DDR with strobe bit */
> +       val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;

In the hs400 function earlier in the file the check to confirm that
the bus width is 8 before doing this.  Should we do that here, too?

> +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                        EXT_CSD_BUS_WIDTH,
> +                        val,
> +                        card->ext_csd.generic_cmd6_time);
> +       if (err) {
> +               pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
> +                       mmc_hostname(host), err);
> +               goto out_err;
> +       }
> +
> +       /* Switch card to HS400 */
> +       val = EXT_CSD_TIMING_HS400 |
> +             card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
> +       err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +                          EXT_CSD_HS_TIMING, val,
> +                          card->ext_csd.generic_cmd6_time,
> +                          true, false, true);
> +       if (err) {
> +               pr_err("%s: switch to hs400es failed, err:%d\n",
> +                       mmc_hostname(host), err);
> +               goto out_err;
> +       }
> +
> +       /* Set host controller to HS400 timing and frequency */
> +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> +
> +       /* Controller enable enhanced strobe function */
> +       host->ios.enhanced_strobe = true;
> +       if (host->ops->hs400_enhanced_strobe)
> +               host->ops->hs400_enhanced_strobe(host, &host->ios);
> +
> +       err = mmc_switch_status(card);
> +       if (err)
> +               goto out_err;
> +
> +       return 0;
> +
> +out_err:
> +       pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
> +              __func__, err);
> +       return err;
> +}
> +
>  static void mmc_select_driver_type(struct mmc_card *card)
>  {
>         int card_drv_type, drive_strength, drv_type;
> @@ -1297,7 +1370,7 @@ err:
>  }
>
>  /*
> - * Activate High Speed or HS200 mode if supported.
> + * Activate High Speed, HS200 or HS400ES mode if supported.
>   */
>  static int mmc_select_timing(struct mmc_card *card)
>  {
> @@ -1306,7 +1379,9 @@ static int mmc_select_timing(struct mmc_card *card)
>         if (!mmc_can_ext_csd(card))
>                 goto bus_speed;
>
> -       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
> +               err = mmc_select_hs400es(card);
> +       else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>                 err = mmc_select_hs200(card);
>         else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>                 err = mmc_select_hs(card);
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index eb0151b..22defc2 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>         u8                      raw_partition_support;  /* 160 */
>         u8                      raw_rpmb_size_mult;     /* 168 */
>         u8                      raw_erased_mem_count;   /* 181 */
> +       u8                      strobe_support;         /* 184 */
>         u8                      raw_ext_csd_structure;  /* 194 */
>         u8                      raw_card_type;          /* 196 */
>         u8                      raw_driver_strength;    /* 197 */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 2a06fb0..f98bd0e 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -19,6 +19,7 @@
>
>  #include <linux/mmc/core.h>
>  #include <linux/mmc/card.h>
> +#include <linux/mmc/mmc.h>
>  #include <linux/mmc/pm.h>
>
>  struct mmc_ios {
> @@ -77,6 +78,8 @@ struct mmc_ios {
>  #define MMC_SET_DRIVER_TYPE_A  1
>  #define MMC_SET_DRIVER_TYPE_C  2
>  #define MMC_SET_DRIVER_TYPE_D  3
> +
> +       bool enhanced_strobe;                   /* hs400es selection */
>  };
>
>  struct mmc_host_ops {
> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>
>         /* Prepare HS400 target operating frequency depending host driver */
>         int     (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
> +       /* Prepare enhanced strobe depending host driver */
> +       void    (*hs400_enhanced_strobe)(struct mmc_host *host,
> +                                        struct mmc_ios *ios);
>         int     (*select_drive_strength)(struct mmc_card *card,
>                                          unsigned int max_dtr, int host_drv,
>                                          int card_drv, int *drv_type);
> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>         return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>  }
>
> +static inline bool mmc_card_hs400es(struct mmc_card *card)
> +{
> +       return card->host->ios.enhanced_strobe == true;

nit: never need "== true".  Just:

  return card->host->ios.enhanced_strobe;

> +}
> +
>  void mmc_retune_timer_stop(struct mmc_host *host);
>
>  static inline void mmc_retune_needed(struct mmc_host *host)
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 15f2c4a..c376209 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -297,6 +297,7 @@ struct _mmc_csd {
>  #define EXT_CSD_PART_CONFIG            179     /* R/W */
>  #define EXT_CSD_ERASED_MEM_CONT                181     /* RO */
>  #define EXT_CSD_BUS_WIDTH              183     /* R/W */
> +#define EXT_CSD_STROBE_SUPPORT         184     /* RO */
>  #define EXT_CSD_HS_TIMING              185     /* R/W */
>  #define EXT_CSD_POWER_CLASS            187     /* R/W */
>  #define EXT_CSD_REV                    192     /* RO */
> @@ -380,12 +381,14 @@ struct _mmc_csd {
>  #define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<7)  /* Card can run at 200MHz DDR, 1.2V */
>  #define EXT_CSD_CARD_TYPE_HS400                (EXT_CSD_CARD_TYPE_HS400_1_8V | \
>                                          EXT_CSD_CARD_TYPE_HS400_1_2V)
> +#define EXT_CSD_CARD_TYPE_HS400ES      (1<<8)  /* Card can run at HS400ES */
>
>  #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
>  #define EXT_CSD_BUS_WIDTH_8    2       /* Card is in 8 bit mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_4        5       /* Card is in 4 bit DDR mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_8        6       /* Card is in 8 bit DDR mode */
> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)        /* Enhanced strobe mode */

nit: while your code should be OK, it seems better to be BIT(3), since
above is really:

0
BIT(0)
BIT(1)
BIT(2) | BIT(0)
BIT(2) | BIT(1)

...at least that's my understanding...


From romieu at fr.zoreil.com  Thu May 19 17:31:45 2016
From: romieu at fr.zoreil.com (Francois Romieu)
Date: Fri, 20 May 2016 02:31:45 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <573E2D0C.604@gmx.de>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com>
 <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com>
 <573E2D0C.604@gmx.de>
Message-ID: <20160520003145.GA22420@electric-eye.fr.zoreil.com>

Lino Sanfilippo <LinoSanfilippo at gmx.de> :
[...]
> 2. requires a smp_wmb, while 3. requires a rmb(). AFAIK the mb() implies all we need, 
> the dma_rmb() for 1., the smp_wmb() for 2. and the rmb() for 3. 

A revalidation of tx_dirty is still needed (see below) despite the rmb()
for 3. The rmb() for 3. is close to useless.

> >> 2. On multi processor systems: ensures that txbd_curr is updated (this is paired
> >>     with the smp_mb() at the end of tx_clean).
> > 
> > Smells like using barrier side-effects to control smp coherency. It isn't
> > the recommended style.
> > 
> 
> As I wrote above, the mb() implies the smp_wmb() so this is a regular pairing
> of smp_wmb() in xmit and smb_mb() in tx_clean, nothing uncommon.

Since you are quoting Documentation/memory-barriers.txt:
[...]
CPU MEMORY BARRIERS
-------------------
[...]
Mandatory barriers should not be used to control SMP effects, since mandatory
barriers impose unnecessary overhead on both SMP and UP systems.

> >> -		if ((info & FOR_EMAC) || !txbd->data || !skb)
> >> +		if (info & FOR_EMAC) {
> >> +			/* Make sure we see consistent values for info, skb
> >> +			 * and data.
> >> +			 */
> >> +			smp_rmb();
> >>  			break;
> >> +		}
> > 
> > ?
> > 
> > smp_rmb should appear before the variables you want coherency for.
> 
> I dont think so. Please take a look into the memory barriers documentation.

> There is an example that is pretty close to the situation that we have in this driver:
> 
> http://lxr.free-electrons.com/source/Documentation/memory-barriers.txt#L1819
> 
> In that example the barrier is also _between_ the variables that are to be
> ordered, not before. 

Err, which barrier ?

- dma_rmb() ?
  The device (obviously) set the 'status' member of the descriptor.
  dma_rmb() ensures that device-initiated DMA is complete for the 'data'
  member as well.

- dma_wmb() ?
  It ensures that the updated 'data' member will be set before any
  DMA resulting from the change of descriptor ownership takes place.

- wmb() ?
  It ensures that the previous write to descriptor (coherent memory)
  completes before write is posted to I/O mailbox.

None of these is "pretty close" to the "smp_rmb() before return" situation.

> >> -	skb_tx_timestamp(skb);
> >> +	/* Make sure info is set after data and skb with respect to
> >> +	 * other tx_clean().
> >> +	 */
> >> +	smp_wmb();
> >>  
> >>  	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
> > 
> > Afaik smp_wmb() does not imply wmb(). So priv->txbd[*txbd_curr].data and
> > *info (aka priv->txbd[*txbd_curr].info) are not necessarily written in
> > an orderly manner.
> 
> Right, as I already wrote above I changed the smp barriers to mandatory ones.
> 
> > 
> >>  
> >> -	/* Make sure info word is set */
> >> -	wmb();
> >> -
> >> -	priv->tx_buff[*txbd_curr].skb = skb;
> >> -
> >>  	/* Increment index to point to the next BD */
> >>  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
> > 
> > With this change it's possible that tx_clean() reads new value for
> > tx_curr and old value (0) for *info.
> 
> Even if this could happen, what is the problem? I cant see an issue
> that results from such a scenario.

tx_clean() misunderstands the 0 in *info as a descriptor updated by the
device. tx_clean() thus kfrees the skb before the device DMAed from it.

[...]
> > Xmit thread                        | Clean thread
> > 
> > mb();
> > 
> > arc_emac_tx_avail() test with old
> > tx_dirty - tx_clean has not issued
> > any mb yet - and new tx_curr
> > 
> >                                      smp_mb();
> > 
> >                                      if (netif_queue_stopped(ndev) && ...
> >                                              netif_wake_queue(ndev);
> > 
> > netif_stop_queue()
> > 
> > -> queue stopped.
> > 
> 
> Again, the mb() we have now implies the smb_mb() we had before. So nothing
> changed except that we can be sure to see the new value for tx_dirty at
> our first attempt.

Nothing changed except you removed the revalidation part !

The smp_mb() we had before wasn't about seeing tx_dirty in the xmit thread
but about balancing the (read) barrier in the cleaning thread so that the
latter stood a chance to see the new (tx thread updated) tx_curr.

Consider the two lines below:

	if (!arc_emac_tx_avail(priv))
		netif_stop_queue(ndev);

Nothing prevents a complete run of the cleaning thread between these
two lines. It may or it may not happen but there is one thing sure:
mb() before arc_emac_tx_avail() can't tell the future.

[...]
> New patch is below. 

The arc_emac_tx_clean() change is wrong.

tx_drity revalidation is still needed in arc_emac_tx after netif_stop_queue.

A barrier is still missing in arc_emac_tx between descriptor release and
tx_curr increase.

-- 
Ueimor


From shawn.lin at rock-chips.com  Thu May 19 18:48:04 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 09:48:04 +0800
Subject: [PATCH v3 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <CAD=FV=Xv-c2owh+dDT1EJYPrKsahxOoQUhJiZFprtk4FxHAK1A@mail.gmail.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
 <1462871391-32484-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=Xv-c2owh+dDT1EJYPrKsahxOoQUhJiZFprtk4FxHAK1A@mail.gmail.com>
Message-ID: <573E6CD4.4010806@rock-chips.com>

Hi

? 2016-5-20 8:18, Doug Anderson ??:
> Hi,
>
> On Tue, May 10, 2016 at 2:09 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> Controllers use data strobe line to latch data from devices
>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>> introduces enhanced strobe mode for latching cmd response from
>> emmc devices to host controllers. This new feature is optional,
>> so it depends both on device's cap and host's cap to decide
>> whether to use it or not.
>
> I don't totally understand it, but two boards I'm working with have
> eMMC devices that claim to be eMMC 5.0 devices but also have support
> for strobe.  Did people just cherry-pick this feature from eMMC 5.1 to
> their eMMC 5.0 devices?

Presumably I guess your "support for strobe" means "support for
enhanced strobe", right?

hs400es is also optional for emmc 5.1, so it's impossible to find a
emmc 5.0 claiming to support hs400es.

Coud you share me the device's ID number on its package or from the
device's manual?


>
>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> ---
>>
>> Changes in v3: None
>> Changes in v2: None
>>
>>   drivers/mmc/core/bus.c   |  3 +-
>>   drivers/mmc/core/core.c  |  8 +++++
>>   drivers/mmc/core/mmc.c   | 79 ++++++++++++++++++++++++++++++++++++++++++++++--
>>   include/linux/mmc/card.h |  1 +
>>   include/linux/mmc/host.h | 11 +++++++
>>   include/linux/mmc/mmc.h  |  3 ++
>>   6 files changed, 102 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> index 4bc48f1..7e94b9d 100644
>> --- a/drivers/mmc/core/bus.c
>> +++ b/drivers/mmc/core/bus.c
>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>                          mmc_card_ddr52(card) ? "DDR " : "",
>>                          type);
>>          } else {
>> -               pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>> +               pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>                          mmc_hostname(card->host),
>>                          mmc_card_uhs(card) ? "ultra high speed " :
>>                          (mmc_card_hs(card) ? "high speed " : ""),
>>                          mmc_card_hs400(card) ? "HS400 " :
>>                          (mmc_card_hs200(card) ? "HS200 " : ""),
>> +                       mmc_card_hs400es(card) ? "Enhanced strobe" : "",
>
> Nit: there should be a space before the quote.  Otherwise the message
> runs together, like:
>
> new HS400 Enhanced strobeMMC card at address 0001

Good catch, thanks.

>
>
>>                          mmc_card_ddr52(card) ? "DDR " : "",
>>                          uhs_bus_speed_mode, type, card->rca);
>>          }
>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> index 99275e4..a559501 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -1127,6 +1127,14 @@ void mmc_set_initial_state(struct mmc_host *host)
>>          host->ios.bus_width = MMC_BUS_WIDTH_1;
>>          host->ios.timing = MMC_TIMING_LEGACY;
>>          host->ios.drv_type = 0;
>> +       host->ios.enhanced_strobe = false;
>> +
>> +       /*
>> +        * Make sure we are in non-enhanced strobe mode before we
>> +        * actually enable it in ext_csd.
>> +        */
>> +       if (host->ops->hs400_enhanced_strobe)
>> +               host->ops->hs400_enhanced_strobe(host, &host->ios);
>>
>>          mmc_set_ios(host);
>>   }
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index f99c47e..c2d1981 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>>                  avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>>          }
>>
>> +       if ((caps2 & MMC_CAP2_HS400_ES) &&
>> +           card->ext_csd.strobe_support &&
>> +           (card_type & EXT_CSD_CARD_TYPE_HS400))
>> +               avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
>> +
>>          card->ext_csd.hs_max_dtr = hs_max_dtr;
>>          card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>>          card->mmc_avail_type = avail_type;
>> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>                          mmc_card_set_blockaddr(card);
>>          }
>>
>> +       card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>>          card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>          mmc_select_card_type(card);
>>
>> @@ -1216,6 +1222,73 @@ out_err:
>>          return err;
>>   }
>>
>> +static int mmc_select_hs400es(struct mmc_card *card)
>> +{
>> +       struct mmc_host *host = card->host;
>> +       int err = 0;
>> +       u8 val;
>> +
>> +       err = mmc_select_bus_width(card);
>> +       if (IS_ERR_VALUE(err))
>> +               goto out_err;
>> +
>> +       /* Switch card to HS mode */
>> +       err = mmc_select_hs(card);
>> +       if (err) {
>> +               pr_err("%s: switch to high-speed failed, err:%d\n",
>> +                       mmc_hostname(host), err);
>> +               goto out_err;
>> +       }
>> +
>> +       err = mmc_switch_status(card);
>> +       if (err)
>> +               goto out_err;
>> +
>> +       /* Switch card to DDR with strobe bit */
>> +       val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
>
> In the hs400 function earlier in the file the check to confirm that
> the bus width is 8 before doing this.  Should we do that here, too?

yes, will fix it. And we can just check host's cap to see
if it supports 8bit before mmc_select_bus_width because we don't
need to do anything without 8-bit support.

>
>> +       err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                        EXT_CSD_BUS_WIDTH,
>> +                        val,
>> +                        card->ext_csd.generic_cmd6_time);
>> +       if (err) {
>> +               pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
>> +                       mmc_hostname(host), err);
>> +               goto out_err;
>> +       }
>> +
>> +       /* Switch card to HS400 */
>> +       val = EXT_CSD_TIMING_HS400 |
>> +             card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
>> +       err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +                          EXT_CSD_HS_TIMING, val,
>> +                          card->ext_csd.generic_cmd6_time,
>> +                          true, false, true);
>> +       if (err) {
>> +               pr_err("%s: switch to hs400es failed, err:%d\n",
>> +                       mmc_hostname(host), err);
>> +               goto out_err;
>> +       }
>> +
>> +       /* Set host controller to HS400 timing and frequency */
>> +       mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>> +
>> +       /* Controller enable enhanced strobe function */
>> +       host->ios.enhanced_strobe = true;
>> +       if (host->ops->hs400_enhanced_strobe)
>> +               host->ops->hs400_enhanced_strobe(host, &host->ios);
>> +
>> +       err = mmc_switch_status(card);
>> +       if (err)
>> +               goto out_err;
>> +
>> +       return 0;
>> +
>> +out_err:
>> +       pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
>> +              __func__, err);
>> +       return err;
>> +}
>> +
>>   static void mmc_select_driver_type(struct mmc_card *card)
>>   {
>>          int card_drv_type, drive_strength, drv_type;
>> @@ -1297,7 +1370,7 @@ err:
>>   }
>>
>>   /*
>> - * Activate High Speed or HS200 mode if supported.
>> + * Activate High Speed, HS200 or HS400ES mode if supported.
>>    */
>>   static int mmc_select_timing(struct mmc_card *card)
>>   {
>> @@ -1306,7 +1379,9 @@ static int mmc_select_timing(struct mmc_card *card)
>>          if (!mmc_can_ext_csd(card))
>>                  goto bus_speed;
>>
>> -       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>> +       if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
>> +               err = mmc_select_hs400es(card);
>> +       else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>                  err = mmc_select_hs200(card);
>>          else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>                  err = mmc_select_hs(card);
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index eb0151b..22defc2 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>>          u8                      raw_partition_support;  /* 160 */
>>          u8                      raw_rpmb_size_mult;     /* 168 */
>>          u8                      raw_erased_mem_count;   /* 181 */
>> +       u8                      strobe_support;         /* 184 */
>>          u8                      raw_ext_csd_structure;  /* 194 */
>>          u8                      raw_card_type;          /* 196 */
>>          u8                      raw_driver_strength;    /* 197 */
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index 2a06fb0..f98bd0e 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -19,6 +19,7 @@
>>
>>   #include <linux/mmc/core.h>
>>   #include <linux/mmc/card.h>
>> +#include <linux/mmc/mmc.h>
>>   #include <linux/mmc/pm.h>
>>
>>   struct mmc_ios {
>> @@ -77,6 +78,8 @@ struct mmc_ios {
>>   #define MMC_SET_DRIVER_TYPE_A  1
>>   #define MMC_SET_DRIVER_TYPE_C  2
>>   #define MMC_SET_DRIVER_TYPE_D  3
>> +
>> +       bool enhanced_strobe;                   /* hs400es selection */
>>   };
>>
>>   struct mmc_host_ops {
>> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>>
>>          /* Prepare HS400 target operating frequency depending host driver */
>>          int     (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>> +       /* Prepare enhanced strobe depending host driver */
>> +       void    (*hs400_enhanced_strobe)(struct mmc_host *host,
>> +                                        struct mmc_ios *ios);
>>          int     (*select_drive_strength)(struct mmc_card *card,
>>                                           unsigned int max_dtr, int host_drv,
>>                                           int card_drv, int *drv_type);
>> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>>          return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>>   }
>>
>> +static inline bool mmc_card_hs400es(struct mmc_card *card)
>> +{
>> +       return card->host->ios.enhanced_strobe == true;
>
> nit: never need "== true".  Just:
>
>    return card->host->ios.enhanced_strobe;
>

yes, thanks.

>> +}
>> +
>>   void mmc_retune_timer_stop(struct mmc_host *host);
>>
>>   static inline void mmc_retune_needed(struct mmc_host *host)
>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> index 15f2c4a..c376209 100644
>> --- a/include/linux/mmc/mmc.h
>> +++ b/include/linux/mmc/mmc.h
>> @@ -297,6 +297,7 @@ struct _mmc_csd {
>>   #define EXT_CSD_PART_CONFIG            179     /* R/W */
>>   #define EXT_CSD_ERASED_MEM_CONT                181     /* RO */
>>   #define EXT_CSD_BUS_WIDTH              183     /* R/W */
>> +#define EXT_CSD_STROBE_SUPPORT         184     /* RO */
>>   #define EXT_CSD_HS_TIMING              185     /* R/W */
>>   #define EXT_CSD_POWER_CLASS            187     /* R/W */
>>   #define EXT_CSD_REV                    192     /* RO */
>> @@ -380,12 +381,14 @@ struct _mmc_csd {
>>   #define EXT_CSD_CARD_TYPE_HS400_1_2V   (1<<7)  /* Card can run at 200MHz DDR, 1.2V */
>>   #define EXT_CSD_CARD_TYPE_HS400                (EXT_CSD_CARD_TYPE_HS400_1_8V | \
>>                                           EXT_CSD_CARD_TYPE_HS400_1_2V)
>> +#define EXT_CSD_CARD_TYPE_HS400ES      (1<<8)  /* Card can run at HS400ES */
>>
>>   #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>>   #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
>>   #define EXT_CSD_BUS_WIDTH_8    2       /* Card is in 8 bit mode */
>>   #define EXT_CSD_DDR_BUS_WIDTH_4        5       /* Card is in 4 bit DDR mode */
>>   #define EXT_CSD_DDR_BUS_WIDTH_8        6       /* Card is in 8 bit DDR mode */
>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)        /* Enhanced strobe mode */
>
> nit: while your code should be OK, it seems better to be BIT(3), since
> above is really:
>

I don't unstand here. EXT_CSD_BUS_WIDTH_STROBE is the MSB of
BUS_WIDTH[183] which is a 8-bit reg.


> 0
> BIT(0)
> BIT(1)
> BIT(2) | BIT(0)
> BIT(2) | BIT(1)
>
> ...at least that's my understanding...
>
>
>



From shawn.lin at rock-chips.com  Thu May 19 18:49:11 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 09:49:11 +0800
Subject: [PATCH v3 5/5] mmc: sdhci-of-arasan: implement enhanced strobe
 callback
In-Reply-To: <CAD=FV=VU7cY+jQ3Tys5vLY_=pP-w5-cKxNTs5JBRxkwr+nVjmQ@mail.gmail.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
 <1462871407-32566-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=VU7cY+jQ3Tys5vLY_=pP-w5-cKxNTs5JBRxkwr+nVjmQ@mail.gmail.com>
Message-ID: <573E6D17.7090601@rock-chips.com>

Hi

? 2016-5-20 8:11, Doug Anderson ??:
> Hi,
>
> On Tue, May 10, 2016 at 2:10 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> Currently sdhci-arasan 5.1 can support enhanced strobe function,
>> and we now limit it just for "arasan,sdhci-5.1". Add
>> mmc-hs400-enhanced-strobe in DT to enable the function if we'r sure
>
> nit:s/we'r/we're/
>
> [ ... ]
>> @@ -79,6 +81,21 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
>>          }
>>   }
>>
>> +static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
>> +                                       struct mmc_ios *ios)
>> +{
>> +       u32 vendor;
>> +       struct sdhci_host *host = mmc_priv(mmc);
>> +
>> +       vendor = readl(host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
>> +       if (ios->enhanced_strobe)
>> +               vendor |= VENDOR_ENHANCED_STROBE;
>> +       else
>> +               vendor &= (~VENDOR_ENHANCED_STROBE);
>
> nit: no extra parentheses:
>
>    vendor &= ~VENDOR_ENHANCED_STROBE;
>
>
> Other than the nits this patch looks good to me.  Feel free to add my
> Reviewed-by when nits fixed.

okay, will fix them.

Thanks for your review!

>
> -Doug
>
>
>



From dianders at chromium.org  Thu May 19 19:19:55 2016
From: dianders at chromium.org (Doug Anderson)
Date: Thu, 19 May 2016 19:19:55 -0700
Subject: [PATCH v3 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <573E6CD4.4010806@rock-chips.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
 <1462871391-32484-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=Xv-c2owh+dDT1EJYPrKsahxOoQUhJiZFprtk4FxHAK1A@mail.gmail.com>
 <573E6CD4.4010806@rock-chips.com>
Message-ID: <CAD=FV=VYsBO21iLZfQkXdFpPy5v-t+k6wP_jD3NZaCz=pEFVww@mail.gmail.com>

Shawn,

On Thu, May 19, 2016 at 6:48 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>>   #define EXT_CSD_BUS_WIDTH_1    0       /* Card is in 1 bit mode */
>>>   #define EXT_CSD_BUS_WIDTH_4    1       /* Card is in 4 bit mode */
>>>   #define EXT_CSD_BUS_WIDTH_8    2       /* Card is in 8 bit mode */
>>>   #define EXT_CSD_DDR_BUS_WIDTH_4        5       /* Card is in 4 bit DDR
>>> mode */
>>>   #define EXT_CSD_DDR_BUS_WIDTH_8        6       /* Card is in 8 bit DDR
>>> mode */
>>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)        /* Enhanced strobe mode
>>> */
>>
>>
>> nit: while your code should be OK, it seems better to be BIT(3), since
>> above is really:
>>
>
> I don't unstand here. EXT_CSD_BUS_WIDTH_STROBE is the MSB of
> BUS_WIDTH[183] which is a 8-bit reg.

I totally misunderstood.  You are correct.

-Doug


From jh80.chung at samsung.com  Thu May 19 19:45:59 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Fri, 20 May 2016 11:45:59 +0900
Subject: [PATCH v3 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <1462871391-32484-1-git-send-email-shawn.lin@rock-chips.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
 <1462871391-32484-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <573E7A67.6050508@samsung.com>

On 05/10/2016 06:09 PM, Shawn Lin wrote:
> Controllers use data strobe line to latch data from devices
> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
> introduces enhanced strobe mode for latching cmd response from
> emmc devices to host controllers. This new feature is optional,
> so it depends both on device's cap and host's cap to decide
> whether to use it or not.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
> 
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/mmc/core/bus.c   |  3 +-
>  drivers/mmc/core/core.c  |  8 +++++
>  drivers/mmc/core/mmc.c   | 79 ++++++++++++++++++++++++++++++++++++++++++++++--
>  include/linux/mmc/card.h |  1 +
>  include/linux/mmc/host.h | 11 +++++++
>  include/linux/mmc/mmc.h  |  3 ++
>  6 files changed, 102 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index 4bc48f1..7e94b9d 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			type);
>  	} else {
> -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>  			mmc_hostname(card->host),
>  			mmc_card_uhs(card) ? "ultra high speed " :
>  			(mmc_card_hs(card) ? "high speed " : ""),
>  			mmc_card_hs400(card) ? "HS400 " :
>  			(mmc_card_hs200(card) ? "HS200 " : ""),
> +			mmc_card_hs400es(card) ? "Enhanced strobe" : "",
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			uhs_bus_speed_mode, type, card->rca);
>  	}
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 99275e4..a559501 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -1127,6 +1127,14 @@ void mmc_set_initial_state(struct mmc_host *host)
>  	host->ios.bus_width = MMC_BUS_WIDTH_1;
>  	host->ios.timing = MMC_TIMING_LEGACY;
>  	host->ios.drv_type = 0;
> +	host->ios.enhanced_strobe = false;
> +
> +	/*
> +	 * Make sure we are in non-enhanced strobe mode before we
> +	 * actually enable it in ext_csd.
> +	 */
> +	if (host->ops->hs400_enhanced_strobe)
> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
>  
>  	mmc_set_ios(host);
>  }
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index f99c47e..c2d1981 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>  		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>  	}
>  
> +	if ((caps2 & MMC_CAP2_HS400_ES) &&
> +	    card->ext_csd.strobe_support &&
> +	    (card_type & EXT_CSD_CARD_TYPE_HS400))
> +		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;

Does it need to check whether support HS400_1.8V/1.2V or not?
It should be more stable than now.

if (avail_type & (EXT_CSD_CARD_TYPE_HS400_1.8V | EXT_CSD_CARD_TYPE_HS400_1.2V)) {
	if ((cap2 & MMC_CAP2_HS400_ES) && ...
}

how about this?

Best Regards,
Jaehoon Chung

> +
>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>  	card->mmc_avail_type = avail_type;
> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>  			mmc_card_set_blockaddr(card);
>  	}
>  
> +	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>  	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>  	mmc_select_card_type(card);
>  
> @@ -1216,6 +1222,73 @@ out_err:
>  	return err;
>  }
>  
> +static int mmc_select_hs400es(struct mmc_card *card)
> +{
> +	struct mmc_host *host = card->host;
> +	int err = 0;
> +	u8 val;
> +
> +	err = mmc_select_bus_width(card);
> +	if (IS_ERR_VALUE(err))
> +		goto out_err;
> +
> +	/* Switch card to HS mode */
> +	err = mmc_select_hs(card);
> +	if (err) {
> +		pr_err("%s: switch to high-speed failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
> +
> +	/* Switch card to DDR with strobe bit */
> +	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			 EXT_CSD_BUS_WIDTH,
> +			 val,
> +			 card->ext_csd.generic_cmd6_time);
> +	if (err) {
> +		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	/* Switch card to HS400 */
> +	val = EXT_CSD_TIMING_HS400 |
> +	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
> +	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			   EXT_CSD_HS_TIMING, val,
> +			   card->ext_csd.generic_cmd6_time,
> +			   true, false, true);
> +	if (err) {
> +		pr_err("%s: switch to hs400es failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	/* Set host controller to HS400 timing and frequency */
> +	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> +
> +	/* Controller enable enhanced strobe function */
> +	host->ios.enhanced_strobe = true;
> +	if (host->ops->hs400_enhanced_strobe)
> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
> +
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
> +
> +	return 0;
> +
> +out_err:
> +	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
> +	       __func__, err);
> +	return err;
> +}
> +
>  static void mmc_select_driver_type(struct mmc_card *card)
>  {
>  	int card_drv_type, drive_strength, drv_type;
> @@ -1297,7 +1370,7 @@ err:
>  }
>  
>  /*
> - * Activate High Speed or HS200 mode if supported.
> + * Activate High Speed, HS200 or HS400ES mode if supported.
>   */
>  static int mmc_select_timing(struct mmc_card *card)
>  {
> @@ -1306,7 +1379,9 @@ static int mmc_select_timing(struct mmc_card *card)
>  	if (!mmc_can_ext_csd(card))
>  		goto bus_speed;
>  
> -	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
> +		err = mmc_select_hs400es(card);
> +	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>  		err = mmc_select_hs200(card);
>  	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>  		err = mmc_select_hs(card);
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index eb0151b..22defc2 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>  	u8			raw_partition_support;	/* 160 */
>  	u8			raw_rpmb_size_mult;	/* 168 */
>  	u8			raw_erased_mem_count;	/* 181 */
> +	u8			strobe_support;		/* 184 */
>  	u8			raw_ext_csd_structure;	/* 194 */
>  	u8			raw_card_type;		/* 196 */
>  	u8			raw_driver_strength;	/* 197 */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 2a06fb0..f98bd0e 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -19,6 +19,7 @@
>  
>  #include <linux/mmc/core.h>
>  #include <linux/mmc/card.h>
> +#include <linux/mmc/mmc.h>
>  #include <linux/mmc/pm.h>
>  
>  struct mmc_ios {
> @@ -77,6 +78,8 @@ struct mmc_ios {
>  #define MMC_SET_DRIVER_TYPE_A	1
>  #define MMC_SET_DRIVER_TYPE_C	2
>  #define MMC_SET_DRIVER_TYPE_D	3
> +
> +	bool enhanced_strobe;			/* hs400es selection */
>  };
>  
>  struct mmc_host_ops {
> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>  
>  	/* Prepare HS400 target operating frequency depending host driver */
>  	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
> +	/* Prepare enhanced strobe depending host driver */
> +	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
> +					 struct mmc_ios *ios);
>  	int	(*select_drive_strength)(struct mmc_card *card,
>  					 unsigned int max_dtr, int host_drv,
>  					 int card_drv, int *drv_type);
> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>  	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>  }
>  
> +static inline bool mmc_card_hs400es(struct mmc_card *card)
> +{
> +	return card->host->ios.enhanced_strobe == true;
> +}
> +
>  void mmc_retune_timer_stop(struct mmc_host *host);
>  
>  static inline void mmc_retune_needed(struct mmc_host *host)
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 15f2c4a..c376209 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -297,6 +297,7 @@ struct _mmc_csd {
>  #define EXT_CSD_PART_CONFIG		179	/* R/W */
>  #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
>  #define EXT_CSD_BUS_WIDTH		183	/* R/W */
> +#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
>  #define EXT_CSD_HS_TIMING		185	/* R/W */
>  #define EXT_CSD_POWER_CLASS		187	/* R/W */
>  #define EXT_CSD_REV			192	/* RO */
> @@ -380,12 +381,14 @@ struct _mmc_csd {
>  #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
>  #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
>  					 EXT_CSD_CARD_TYPE_HS400_1_2V)
> +#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
>  
>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
>  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
>  
>  #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
>  #define EXT_CSD_TIMING_HS	1	/* High speed */
> 



From shawn.lin at rock-chips.com  Thu May 19 20:15:40 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 11:15:40 +0800
Subject: [PATCH v3 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <573E7A67.6050508@samsung.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
 <1462871391-32484-1-git-send-email-shawn.lin@rock-chips.com>
 <573E7A67.6050508@samsung.com>
Message-ID: <573E815C.5080204@rock-chips.com>

Hi

? 2016-5-20 10:45, Jaehoon Chung ??:
> On 05/10/2016 06:09 PM, Shawn Lin wrote:
>> Controllers use data strobe line to latch data from devices
>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>> introduces enhanced strobe mode for latching cmd response from
>> emmc devices to host controllers. This new feature is optional,
>> so it depends both on device's cap and host's cap to decide
>> whether to use it or not.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> ---
>>
>> Changes in v3: None
>> Changes in v2: None
>>
>>   drivers/mmc/core/bus.c   |  3 +-
>>   drivers/mmc/core/core.c  |  8 +++++
>>   drivers/mmc/core/mmc.c   | 79 ++++++++++++++++++++++++++++++++++++++++++++++--
>>   include/linux/mmc/card.h |  1 +
>>   include/linux/mmc/host.h | 11 +++++++
>>   include/linux/mmc/mmc.h  |  3 ++
>>   6 files changed, 102 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> index 4bc48f1..7e94b9d 100644
>> --- a/drivers/mmc/core/bus.c
>> +++ b/drivers/mmc/core/bus.c
>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>   			mmc_card_ddr52(card) ? "DDR " : "",
>>   			type);
>>   	} else {
>> -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>> +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>   			mmc_hostname(card->host),
>>   			mmc_card_uhs(card) ? "ultra high speed " :
>>   			(mmc_card_hs(card) ? "high speed " : ""),
>>   			mmc_card_hs400(card) ? "HS400 " :
>>   			(mmc_card_hs200(card) ? "HS200 " : ""),
>> +			mmc_card_hs400es(card) ? "Enhanced strobe" : "",
>>   			mmc_card_ddr52(card) ? "DDR " : "",
>>   			uhs_bus_speed_mode, type, card->rca);
>>   	}
>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> index 99275e4..a559501 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -1127,6 +1127,14 @@ void mmc_set_initial_state(struct mmc_host *host)
>>   	host->ios.bus_width = MMC_BUS_WIDTH_1;
>>   	host->ios.timing = MMC_TIMING_LEGACY;
>>   	host->ios.drv_type = 0;
>> +	host->ios.enhanced_strobe = false;
>> +
>> +	/*
>> +	 * Make sure we are in non-enhanced strobe mode before we
>> +	 * actually enable it in ext_csd.
>> +	 */
>> +	if (host->ops->hs400_enhanced_strobe)
>> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
>>
>>   	mmc_set_ios(host);
>>   }
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index f99c47e..c2d1981 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>>   		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>>   	}
>>
>> +	if ((caps2 & MMC_CAP2_HS400_ES) &&
>> +	    card->ext_csd.strobe_support &&
>> +	    (card_type & EXT_CSD_CARD_TYPE_HS400))
>> +		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
>
> Does it need to check whether support HS400_1.8V/1.2V or not?
> It should be more stable than now.
>

Ahh, right.
I need to add "avail_type & EXT_CSD_CARD_TYPE_HS400" instead of
"card_type & EXT_CSD_CARD_TYPE_HS400"... because if "avail_type &
EXT_CSD_CARD_TYPE_HS400" is true, it implies that "card_type & 
EXT_CSD_CARD_TYPE_HS400" must be true.


Thansk for catching this!


> if (avail_type & (EXT_CSD_CARD_TYPE_HS400_1.8V | EXT_CSD_CARD_TYPE_HS400_1.2V)) {
> 	if ((cap2 & MMC_CAP2_HS400_ES) && ...
> }
>
> how about this?
>
> Best Regards,
> Jaehoon Chung
>
>> +
>>   	card->ext_csd.hs_max_dtr = hs_max_dtr;
>>   	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>>   	card->mmc_avail_type = avail_type;
>> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>   			mmc_card_set_blockaddr(card);
>>   	}
>>
>> +	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>>   	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>   	mmc_select_card_type(card);
>>
>> @@ -1216,6 +1222,73 @@ out_err:
>>   	return err;
>>   }
>>
>> +static int mmc_select_hs400es(struct mmc_card *card)
>> +{
>> +	struct mmc_host *host = card->host;
>> +	int err = 0;
>> +	u8 val;
>> +
>> +	err = mmc_select_bus_width(card);
>> +	if (IS_ERR_VALUE(err))
>> +		goto out_err;
>> +
>> +	/* Switch card to HS mode */
>> +	err = mmc_select_hs(card);
>> +	if (err) {
>> +		pr_err("%s: switch to high-speed failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	err = mmc_switch_status(card);
>> +	if (err)
>> +		goto out_err;
>> +
>> +	/* Switch card to DDR with strobe bit */
>> +	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
>> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +			 EXT_CSD_BUS_WIDTH,
>> +			 val,
>> +			 card->ext_csd.generic_cmd6_time);
>> +	if (err) {
>> +		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	/* Switch card to HS400 */
>> +	val = EXT_CSD_TIMING_HS400 |
>> +	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
>> +	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +			   EXT_CSD_HS_TIMING, val,
>> +			   card->ext_csd.generic_cmd6_time,
>> +			   true, false, true);
>> +	if (err) {
>> +		pr_err("%s: switch to hs400es failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	/* Set host controller to HS400 timing and frequency */
>> +	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>> +
>> +	/* Controller enable enhanced strobe function */
>> +	host->ios.enhanced_strobe = true;
>> +	if (host->ops->hs400_enhanced_strobe)
>> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
>> +
>> +	err = mmc_switch_status(card);
>> +	if (err)
>> +		goto out_err;
>> +
>> +	return 0;
>> +
>> +out_err:
>> +	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
>> +	       __func__, err);
>> +	return err;
>> +}
>> +
>>   static void mmc_select_driver_type(struct mmc_card *card)
>>   {
>>   	int card_drv_type, drive_strength, drv_type;
>> @@ -1297,7 +1370,7 @@ err:
>>   }
>>
>>   /*
>> - * Activate High Speed or HS200 mode if supported.
>> + * Activate High Speed, HS200 or HS400ES mode if supported.
>>    */
>>   static int mmc_select_timing(struct mmc_card *card)
>>   {
>> @@ -1306,7 +1379,9 @@ static int mmc_select_timing(struct mmc_card *card)
>>   	if (!mmc_can_ext_csd(card))
>>   		goto bus_speed;
>>
>> -	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
>> +		err = mmc_select_hs400es(card);
>> +	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>   		err = mmc_select_hs200(card);
>>   	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>   		err = mmc_select_hs(card);
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index eb0151b..22defc2 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>>   	u8			raw_partition_support;	/* 160 */
>>   	u8			raw_rpmb_size_mult;	/* 168 */
>>   	u8			raw_erased_mem_count;	/* 181 */
>> +	u8			strobe_support;		/* 184 */
>>   	u8			raw_ext_csd_structure;	/* 194 */
>>   	u8			raw_card_type;		/* 196 */
>>   	u8			raw_driver_strength;	/* 197 */
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index 2a06fb0..f98bd0e 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -19,6 +19,7 @@
>>
>>   #include <linux/mmc/core.h>
>>   #include <linux/mmc/card.h>
>> +#include <linux/mmc/mmc.h>
>>   #include <linux/mmc/pm.h>
>>
>>   struct mmc_ios {
>> @@ -77,6 +78,8 @@ struct mmc_ios {
>>   #define MMC_SET_DRIVER_TYPE_A	1
>>   #define MMC_SET_DRIVER_TYPE_C	2
>>   #define MMC_SET_DRIVER_TYPE_D	3
>> +
>> +	bool enhanced_strobe;			/* hs400es selection */
>>   };
>>
>>   struct mmc_host_ops {
>> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>>
>>   	/* Prepare HS400 target operating frequency depending host driver */
>>   	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>> +	/* Prepare enhanced strobe depending host driver */
>> +	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
>> +					 struct mmc_ios *ios);
>>   	int	(*select_drive_strength)(struct mmc_card *card,
>>   					 unsigned int max_dtr, int host_drv,
>>   					 int card_drv, int *drv_type);
>> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>>   	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>>   }
>>
>> +static inline bool mmc_card_hs400es(struct mmc_card *card)
>> +{
>> +	return card->host->ios.enhanced_strobe == true;
>> +}
>> +
>>   void mmc_retune_timer_stop(struct mmc_host *host);
>>
>>   static inline void mmc_retune_needed(struct mmc_host *host)
>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> index 15f2c4a..c376209 100644
>> --- a/include/linux/mmc/mmc.h
>> +++ b/include/linux/mmc/mmc.h
>> @@ -297,6 +297,7 @@ struct _mmc_csd {
>>   #define EXT_CSD_PART_CONFIG		179	/* R/W */
>>   #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
>>   #define EXT_CSD_BUS_WIDTH		183	/* R/W */
>> +#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
>>   #define EXT_CSD_HS_TIMING		185	/* R/W */
>>   #define EXT_CSD_POWER_CLASS		187	/* R/W */
>>   #define EXT_CSD_REV			192	/* RO */
>> @@ -380,12 +381,14 @@ struct _mmc_csd {
>>   #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
>>   #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
>>   					 EXT_CSD_CARD_TYPE_HS400_1_2V)
>> +#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
>>
>>   #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>>   #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
>>   #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
>>   #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
>>   #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
>>
>>   #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
>>   #define EXT_CSD_TIMING_HS	1	/* High speed */
>>
>
>
>
>



From jh80.chung at samsung.com  Thu May 19 20:54:37 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Fri, 20 May 2016 12:54:37 +0900
Subject: [PATCH v3 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <573E815C.5080204@rock-chips.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
 <1462871391-32484-1-git-send-email-shawn.lin@rock-chips.com>
 <573E7A67.6050508@samsung.com> <573E815C.5080204@rock-chips.com>
Message-ID: <573E8A7D.3040308@samsung.com>

On 05/20/2016 12:15 PM, Shawn Lin wrote:
> Hi
> 
> ? 2016-5-20 10:45, Jaehoon Chung ??:
>> On 05/10/2016 06:09 PM, Shawn Lin wrote:
>>> Controllers use data strobe line to latch data from devices
>>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>>> introduces enhanced strobe mode for latching cmd response from
>>> emmc devices to host controllers. This new feature is optional,
>>> so it depends both on device's cap and host's cap to decide
>>> whether to use it or not.
>>>
>>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>> ---
>>>
>>> Changes in v3: None
>>> Changes in v2: None
>>>
>>>   drivers/mmc/core/bus.c   |  3 +-
>>>   drivers/mmc/core/core.c  |  8 +++++
>>>   drivers/mmc/core/mmc.c   | 79 ++++++++++++++++++++++++++++++++++++++++++++++--
>>>   include/linux/mmc/card.h |  1 +
>>>   include/linux/mmc/host.h | 11 +++++++
>>>   include/linux/mmc/mmc.h  |  3 ++
>>>   6 files changed, 102 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>>> index 4bc48f1..7e94b9d 100644
>>> --- a/drivers/mmc/core/bus.c
>>> +++ b/drivers/mmc/core/bus.c
>>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>>               mmc_card_ddr52(card) ? "DDR " : "",
>>>               type);
>>>       } else {
>>> -        pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>>> +        pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>>               mmc_hostname(card->host),
>>>               mmc_card_uhs(card) ? "ultra high speed " :
>>>               (mmc_card_hs(card) ? "high speed " : ""),
>>>               mmc_card_hs400(card) ? "HS400 " :
>>>               (mmc_card_hs200(card) ? "HS200 " : ""),
>>> +            mmc_card_hs400es(card) ? "Enhanced strobe" : "",
>>>               mmc_card_ddr52(card) ? "DDR " : "",
>>>               uhs_bus_speed_mode, type, card->rca);
>>>       }
>>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>>> index 99275e4..a559501 100644
>>> --- a/drivers/mmc/core/core.c
>>> +++ b/drivers/mmc/core/core.c
>>> @@ -1127,6 +1127,14 @@ void mmc_set_initial_state(struct mmc_host *host)
>>>       host->ios.bus_width = MMC_BUS_WIDTH_1;
>>>       host->ios.timing = MMC_TIMING_LEGACY;
>>>       host->ios.drv_type = 0;
>>> +    host->ios.enhanced_strobe = false;
>>> +
>>> +    /*
>>> +     * Make sure we are in non-enhanced strobe mode before we
>>> +     * actually enable it in ext_csd.
>>> +     */
>>> +    if (host->ops->hs400_enhanced_strobe)
>>> +        host->ops->hs400_enhanced_strobe(host, &host->ios);
>>>
>>>       mmc_set_ios(host);
>>>   }
>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>> index f99c47e..c2d1981 100644
>>> --- a/drivers/mmc/core/mmc.c
>>> +++ b/drivers/mmc/core/mmc.c
>>> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>>>           avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>>>       }
>>>
>>> +    if ((caps2 & MMC_CAP2_HS400_ES) &&
>>> +        card->ext_csd.strobe_support &&
>>> +        (card_type & EXT_CSD_CARD_TYPE_HS400))
>>> +        avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
>>
>> Does it need to check whether support HS400_1.8V/1.2V or not?
>> It should be more stable than now.
>>
> 
> Ahh, right.
> I need to add "avail_type & EXT_CSD_CARD_TYPE_HS400" instead of
> "card_type & EXT_CSD_CARD_TYPE_HS400"... because if "avail_type &
> EXT_CSD_CARD_TYPE_HS400" is true, it implies that "card_type & EXT_CSD_CARD_TYPE_HS400" must be true.

Otherwise, you can check or add the capabilities in the parse_of_mmc().
It can choose according to your preference. :)

Anyway, i have tested your patches..If you send the patch V4, i will also test.

Best Regards,
Jaehoon Chung

> 
> 
> Thansk for catching this!
> 
> 
>> if (avail_type & (EXT_CSD_CARD_TYPE_HS400_1.8V | EXT_CSD_CARD_TYPE_HS400_1.2V)) {
>>     if ((cap2 & MMC_CAP2_HS400_ES) && ...
>> }
>>
>> how about this?
>>
>> Best Regards,
>> Jaehoon Chung
>>
>>> +
>>>       card->ext_csd.hs_max_dtr = hs_max_dtr;
>>>       card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>>>       card->mmc_avail_type = avail_type;
>>> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>>               mmc_card_set_blockaddr(card);
>>>       }
>>>
>>> +    card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>>>       card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>>       mmc_select_card_type(card);
>>>
>>> @@ -1216,6 +1222,73 @@ out_err:
>>>       return err;
>>>   }
>>>
>>> +static int mmc_select_hs400es(struct mmc_card *card)
>>> +{
>>> +    struct mmc_host *host = card->host;
>>> +    int err = 0;
>>> +    u8 val;
>>> +
>>> +    err = mmc_select_bus_width(card);
>>> +    if (IS_ERR_VALUE(err))
>>> +        goto out_err;
>>> +
>>> +    /* Switch card to HS mode */
>>> +    err = mmc_select_hs(card);
>>> +    if (err) {
>>> +        pr_err("%s: switch to high-speed failed, err:%d\n",
>>> +            mmc_hostname(host), err);
>>> +        goto out_err;
>>> +    }
>>> +
>>> +    err = mmc_switch_status(card);
>>> +    if (err)
>>> +        goto out_err;
>>> +
>>> +    /* Switch card to DDR with strobe bit */
>>> +    val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
>>> +    err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>> +             EXT_CSD_BUS_WIDTH,
>>> +             val,
>>> +             card->ext_csd.generic_cmd6_time);
>>> +    if (err) {
>>> +        pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
>>> +            mmc_hostname(host), err);
>>> +        goto out_err;
>>> +    }
>>> +
>>> +    /* Switch card to HS400 */
>>> +    val = EXT_CSD_TIMING_HS400 |
>>> +          card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
>>> +    err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>> +               EXT_CSD_HS_TIMING, val,
>>> +               card->ext_csd.generic_cmd6_time,
>>> +               true, false, true);
>>> +    if (err) {
>>> +        pr_err("%s: switch to hs400es failed, err:%d\n",
>>> +            mmc_hostname(host), err);
>>> +        goto out_err;
>>> +    }
>>> +
>>> +    /* Set host controller to HS400 timing and frequency */
>>> +    mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>>> +
>>> +    /* Controller enable enhanced strobe function */
>>> +    host->ios.enhanced_strobe = true;
>>> +    if (host->ops->hs400_enhanced_strobe)
>>> +        host->ops->hs400_enhanced_strobe(host, &host->ios);
>>> +
>>> +    err = mmc_switch_status(card);
>>> +    if (err)
>>> +        goto out_err;
>>> +
>>> +    return 0;
>>> +
>>> +out_err:
>>> +    pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
>>> +           __func__, err);
>>> +    return err;
>>> +}
>>> +
>>>   static void mmc_select_driver_type(struct mmc_card *card)
>>>   {
>>>       int card_drv_type, drive_strength, drv_type;
>>> @@ -1297,7 +1370,7 @@ err:
>>>   }
>>>
>>>   /*
>>> - * Activate High Speed or HS200 mode if supported.
>>> + * Activate High Speed, HS200 or HS400ES mode if supported.
>>>    */
>>>   static int mmc_select_timing(struct mmc_card *card)
>>>   {
>>> @@ -1306,7 +1379,9 @@ static int mmc_select_timing(struct mmc_card *card)
>>>       if (!mmc_can_ext_csd(card))
>>>           goto bus_speed;
>>>
>>> -    if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>> +    if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
>>> +        err = mmc_select_hs400es(card);
>>> +    else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>>           err = mmc_select_hs200(card);
>>>       else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>>           err = mmc_select_hs(card);
>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>>> index eb0151b..22defc2 100644
>>> --- a/include/linux/mmc/card.h
>>> +++ b/include/linux/mmc/card.h
>>> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>>>       u8            raw_partition_support;    /* 160 */
>>>       u8            raw_rpmb_size_mult;    /* 168 */
>>>       u8            raw_erased_mem_count;    /* 181 */
>>> +    u8            strobe_support;        /* 184 */
>>>       u8            raw_ext_csd_structure;    /* 194 */
>>>       u8            raw_card_type;        /* 196 */
>>>       u8            raw_driver_strength;    /* 197 */
>>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>>> index 2a06fb0..f98bd0e 100644
>>> --- a/include/linux/mmc/host.h
>>> +++ b/include/linux/mmc/host.h
>>> @@ -19,6 +19,7 @@
>>>
>>>   #include <linux/mmc/core.h>
>>>   #include <linux/mmc/card.h>
>>> +#include <linux/mmc/mmc.h>
>>>   #include <linux/mmc/pm.h>
>>>
>>>   struct mmc_ios {
>>> @@ -77,6 +78,8 @@ struct mmc_ios {
>>>   #define MMC_SET_DRIVER_TYPE_A    1
>>>   #define MMC_SET_DRIVER_TYPE_C    2
>>>   #define MMC_SET_DRIVER_TYPE_D    3
>>> +
>>> +    bool enhanced_strobe;            /* hs400es selection */
>>>   };
>>>
>>>   struct mmc_host_ops {
>>> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>>>
>>>       /* Prepare HS400 target operating frequency depending host driver */
>>>       int    (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>>> +    /* Prepare enhanced strobe depending host driver */
>>> +    void    (*hs400_enhanced_strobe)(struct mmc_host *host,
>>> +                     struct mmc_ios *ios);
>>>       int    (*select_drive_strength)(struct mmc_card *card,
>>>                        unsigned int max_dtr, int host_drv,
>>>                        int card_drv, int *drv_type);
>>> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>>>       return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>>>   }
>>>
>>> +static inline bool mmc_card_hs400es(struct mmc_card *card)
>>> +{
>>> +    return card->host->ios.enhanced_strobe == true;
>>> +}
>>> +
>>>   void mmc_retune_timer_stop(struct mmc_host *host);
>>>
>>>   static inline void mmc_retune_needed(struct mmc_host *host)
>>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>>> index 15f2c4a..c376209 100644
>>> --- a/include/linux/mmc/mmc.h
>>> +++ b/include/linux/mmc/mmc.h
>>> @@ -297,6 +297,7 @@ struct _mmc_csd {
>>>   #define EXT_CSD_PART_CONFIG        179    /* R/W */
>>>   #define EXT_CSD_ERASED_MEM_CONT        181    /* RO */
>>>   #define EXT_CSD_BUS_WIDTH        183    /* R/W */
>>> +#define EXT_CSD_STROBE_SUPPORT        184    /* RO */
>>>   #define EXT_CSD_HS_TIMING        185    /* R/W */
>>>   #define EXT_CSD_POWER_CLASS        187    /* R/W */
>>>   #define EXT_CSD_REV            192    /* RO */
>>> @@ -380,12 +381,14 @@ struct _mmc_csd {
>>>   #define EXT_CSD_CARD_TYPE_HS400_1_2V    (1<<7)    /* Card can run at 200MHz DDR, 1.2V */
>>>   #define EXT_CSD_CARD_TYPE_HS400        (EXT_CSD_CARD_TYPE_HS400_1_8V | \
>>>                        EXT_CSD_CARD_TYPE_HS400_1_2V)
>>> +#define EXT_CSD_CARD_TYPE_HS400ES    (1<<8)    /* Card can run at HS400ES */
>>>
>>>   #define EXT_CSD_BUS_WIDTH_1    0    /* Card is in 1 bit mode */
>>>   #define EXT_CSD_BUS_WIDTH_4    1    /* Card is in 4 bit mode */
>>>   #define EXT_CSD_BUS_WIDTH_8    2    /* Card is in 8 bit mode */
>>>   #define EXT_CSD_DDR_BUS_WIDTH_4    5    /* Card is in 4 bit DDR mode */
>>>   #define EXT_CSD_DDR_BUS_WIDTH_8    6    /* Card is in 8 bit DDR mode */
>>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)    /* Enhanced strobe mode */
>>>
>>>   #define EXT_CSD_TIMING_BC    0    /* Backwards compatility */
>>>   #define EXT_CSD_TIMING_HS    1    /* High speed */
>>>
>>
>>
>>
>>
> 
> -- 
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
> 



From shawn.lin at rock-chips.com  Thu May 19 21:15:46 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 12:15:46 +0800
Subject: [PATCH v3 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <573E8A7D.3040308@samsung.com>
References: <1462871343-32361-1-git-send-email-shawn.lin@rock-chips.com>
 <1462871391-32484-1-git-send-email-shawn.lin@rock-chips.com>
 <573E7A67.6050508@samsung.com> <573E815C.5080204@rock-chips.com>
 <573E8A7D.3040308@samsung.com>
Message-ID: <573E8F72.3000407@rock-chips.com>

Hi

? 2016-5-20 11:54, Jaehoon Chung ??:
> On 05/20/2016 12:15 PM, Shawn Lin wrote:
>> Hi
>>
>> ? 2016-5-20 10:45, Jaehoon Chung ??:
>>> On 05/10/2016 06:09 PM, Shawn Lin wrote:
>>>> Controllers use data strobe line to latch data from devices
>>>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>>>> introduces enhanced strobe mode for latching cmd response from
>>>> emmc devices to host controllers. This new feature is optional,
>>>> so it depends both on device's cap and host's cap to decide
>>>> whether to use it or not.
>>>>
>>>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>>> ---
>>>>
>>>> Changes in v3: None
>>>> Changes in v2: None
>>>>
>>>>    drivers/mmc/core/bus.c   |  3 +-
>>>>    drivers/mmc/core/core.c  |  8 +++++
>>>>    drivers/mmc/core/mmc.c   | 79 ++++++++++++++++++++++++++++++++++++++++++++++--
>>>>    include/linux/mmc/card.h |  1 +
>>>>    include/linux/mmc/host.h | 11 +++++++
>>>>    include/linux/mmc/mmc.h  |  3 ++
>>>>    6 files changed, 102 insertions(+), 3 deletions(-)
>>>>
>>>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>>>> index 4bc48f1..7e94b9d 100644
>>>> --- a/drivers/mmc/core/bus.c
>>>> +++ b/drivers/mmc/core/bus.c
>>>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>>>                mmc_card_ddr52(card) ? "DDR " : "",
>>>>                type);
>>>>        } else {
>>>> -        pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>>>> +        pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>>>                mmc_hostname(card->host),
>>>>                mmc_card_uhs(card) ? "ultra high speed " :
>>>>                (mmc_card_hs(card) ? "high speed " : ""),
>>>>                mmc_card_hs400(card) ? "HS400 " :
>>>>                (mmc_card_hs200(card) ? "HS200 " : ""),
>>>> +            mmc_card_hs400es(card) ? "Enhanced strobe" : "",
>>>>                mmc_card_ddr52(card) ? "DDR " : "",
>>>>                uhs_bus_speed_mode, type, card->rca);
>>>>        }
>>>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>>>> index 99275e4..a559501 100644
>>>> --- a/drivers/mmc/core/core.c
>>>> +++ b/drivers/mmc/core/core.c
>>>> @@ -1127,6 +1127,14 @@ void mmc_set_initial_state(struct mmc_host *host)
>>>>        host->ios.bus_width = MMC_BUS_WIDTH_1;
>>>>        host->ios.timing = MMC_TIMING_LEGACY;
>>>>        host->ios.drv_type = 0;
>>>> +    host->ios.enhanced_strobe = false;
>>>> +
>>>> +    /*
>>>> +     * Make sure we are in non-enhanced strobe mode before we
>>>> +     * actually enable it in ext_csd.
>>>> +     */
>>>> +    if (host->ops->hs400_enhanced_strobe)
>>>> +        host->ops->hs400_enhanced_strobe(host, &host->ios);
>>>>
>>>>        mmc_set_ios(host);
>>>>    }
>>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>>> index f99c47e..c2d1981 100644
>>>> --- a/drivers/mmc/core/mmc.c
>>>> +++ b/drivers/mmc/core/mmc.c
>>>> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>>>>            avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>>>>        }
>>>>
>>>> +    if ((caps2 & MMC_CAP2_HS400_ES) &&
>>>> +        card->ext_csd.strobe_support &&
>>>> +        (card_type & EXT_CSD_CARD_TYPE_HS400))
>>>> +        avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
>>>
>>> Does it need to check whether support HS400_1.8V/1.2V or not?
>>> It should be more stable than now.
>>>
>>
>> Ahh, right.
>> I need to add "avail_type & EXT_CSD_CARD_TYPE_HS400" instead of
>> "card_type & EXT_CSD_CARD_TYPE_HS400"... because if "avail_type &
>> EXT_CSD_CARD_TYPE_HS400" is true, it implies that "card_type & EXT_CSD_CARD_TYPE_HS400" must be true.
>
> Otherwise, you can check or add the capabilities in the parse_of_mmc().
> It can choose according to your preference. :)
>
> Anyway, i have tested your patches..If you send the patch V4, i will also test.

Thanks for testing. I will cc you when pushing V4.

>
> Best Regards,
> Jaehoon Chung
>
>>
>>
>> Thansk for catching this!
>>
>>
>>> if (avail_type & (EXT_CSD_CARD_TYPE_HS400_1.8V | EXT_CSD_CARD_TYPE_HS400_1.2V)) {
>>>      if ((cap2 & MMC_CAP2_HS400_ES) && ...
>>> }
>>>
>>> how about this?
>>>
>>> Best Regards,
>>> Jaehoon Chung
>>>
>>>> +
>>>>        card->ext_csd.hs_max_dtr = hs_max_dtr;
>>>>        card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>>>>        card->mmc_avail_type = avail_type;
>>>> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>>>                mmc_card_set_blockaddr(card);
>>>>        }
>>>>
>>>> +    card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>>>>        card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>>>        mmc_select_card_type(card);
>>>>
>>>> @@ -1216,6 +1222,73 @@ out_err:
>>>>        return err;
>>>>    }
>>>>
>>>> +static int mmc_select_hs400es(struct mmc_card *card)
>>>> +{
>>>> +    struct mmc_host *host = card->host;
>>>> +    int err = 0;
>>>> +    u8 val;
>>>> +
>>>> +    err = mmc_select_bus_width(card);
>>>> +    if (IS_ERR_VALUE(err))
>>>> +        goto out_err;
>>>> +
>>>> +    /* Switch card to HS mode */
>>>> +    err = mmc_select_hs(card);
>>>> +    if (err) {
>>>> +        pr_err("%s: switch to high-speed failed, err:%d\n",
>>>> +            mmc_hostname(host), err);
>>>> +        goto out_err;
>>>> +    }
>>>> +
>>>> +    err = mmc_switch_status(card);
>>>> +    if (err)
>>>> +        goto out_err;
>>>> +
>>>> +    /* Switch card to DDR with strobe bit */
>>>> +    val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
>>>> +    err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>>> +             EXT_CSD_BUS_WIDTH,
>>>> +             val,
>>>> +             card->ext_csd.generic_cmd6_time);
>>>> +    if (err) {
>>>> +        pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
>>>> +            mmc_hostname(host), err);
>>>> +        goto out_err;
>>>> +    }
>>>> +
>>>> +    /* Switch card to HS400 */
>>>> +    val = EXT_CSD_TIMING_HS400 |
>>>> +          card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
>>>> +    err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>>> +               EXT_CSD_HS_TIMING, val,
>>>> +               card->ext_csd.generic_cmd6_time,
>>>> +               true, false, true);
>>>> +    if (err) {
>>>> +        pr_err("%s: switch to hs400es failed, err:%d\n",
>>>> +            mmc_hostname(host), err);
>>>> +        goto out_err;
>>>> +    }
>>>> +
>>>> +    /* Set host controller to HS400 timing and frequency */
>>>> +    mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>>>> +
>>>> +    /* Controller enable enhanced strobe function */
>>>> +    host->ios.enhanced_strobe = true;
>>>> +    if (host->ops->hs400_enhanced_strobe)
>>>> +        host->ops->hs400_enhanced_strobe(host, &host->ios);
>>>> +
>>>> +    err = mmc_switch_status(card);
>>>> +    if (err)
>>>> +        goto out_err;
>>>> +
>>>> +    return 0;
>>>> +
>>>> +out_err:
>>>> +    pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
>>>> +           __func__, err);
>>>> +    return err;
>>>> +}
>>>> +
>>>>    static void mmc_select_driver_type(struct mmc_card *card)
>>>>    {
>>>>        int card_drv_type, drive_strength, drv_type;
>>>> @@ -1297,7 +1370,7 @@ err:
>>>>    }
>>>>
>>>>    /*
>>>> - * Activate High Speed or HS200 mode if supported.
>>>> + * Activate High Speed, HS200 or HS400ES mode if supported.
>>>>     */
>>>>    static int mmc_select_timing(struct mmc_card *card)
>>>>    {
>>>> @@ -1306,7 +1379,9 @@ static int mmc_select_timing(struct mmc_card *card)
>>>>        if (!mmc_can_ext_csd(card))
>>>>            goto bus_speed;
>>>>
>>>> -    if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>>> +    if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
>>>> +        err = mmc_select_hs400es(card);
>>>> +    else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>>>            err = mmc_select_hs200(card);
>>>>        else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>>>            err = mmc_select_hs(card);
>>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>>>> index eb0151b..22defc2 100644
>>>> --- a/include/linux/mmc/card.h
>>>> +++ b/include/linux/mmc/card.h
>>>> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>>>>        u8            raw_partition_support;    /* 160 */
>>>>        u8            raw_rpmb_size_mult;    /* 168 */
>>>>        u8            raw_erased_mem_count;    /* 181 */
>>>> +    u8            strobe_support;        /* 184 */
>>>>        u8            raw_ext_csd_structure;    /* 194 */
>>>>        u8            raw_card_type;        /* 196 */
>>>>        u8            raw_driver_strength;    /* 197 */
>>>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>>>> index 2a06fb0..f98bd0e 100644
>>>> --- a/include/linux/mmc/host.h
>>>> +++ b/include/linux/mmc/host.h
>>>> @@ -19,6 +19,7 @@
>>>>
>>>>    #include <linux/mmc/core.h>
>>>>    #include <linux/mmc/card.h>
>>>> +#include <linux/mmc/mmc.h>
>>>>    #include <linux/mmc/pm.h>
>>>>
>>>>    struct mmc_ios {
>>>> @@ -77,6 +78,8 @@ struct mmc_ios {
>>>>    #define MMC_SET_DRIVER_TYPE_A    1
>>>>    #define MMC_SET_DRIVER_TYPE_C    2
>>>>    #define MMC_SET_DRIVER_TYPE_D    3
>>>> +
>>>> +    bool enhanced_strobe;            /* hs400es selection */
>>>>    };
>>>>
>>>>    struct mmc_host_ops {
>>>> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>>>>
>>>>        /* Prepare HS400 target operating frequency depending host driver */
>>>>        int    (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>>>> +    /* Prepare enhanced strobe depending host driver */
>>>> +    void    (*hs400_enhanced_strobe)(struct mmc_host *host,
>>>> +                     struct mmc_ios *ios);
>>>>        int    (*select_drive_strength)(struct mmc_card *card,
>>>>                         unsigned int max_dtr, int host_drv,
>>>>                         int card_drv, int *drv_type);
>>>> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>>>>        return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>>>>    }
>>>>
>>>> +static inline bool mmc_card_hs400es(struct mmc_card *card)
>>>> +{
>>>> +    return card->host->ios.enhanced_strobe == true;
>>>> +}
>>>> +
>>>>    void mmc_retune_timer_stop(struct mmc_host *host);
>>>>
>>>>    static inline void mmc_retune_needed(struct mmc_host *host)
>>>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>>>> index 15f2c4a..c376209 100644
>>>> --- a/include/linux/mmc/mmc.h
>>>> +++ b/include/linux/mmc/mmc.h
>>>> @@ -297,6 +297,7 @@ struct _mmc_csd {
>>>>    #define EXT_CSD_PART_CONFIG        179    /* R/W */
>>>>    #define EXT_CSD_ERASED_MEM_CONT        181    /* RO */
>>>>    #define EXT_CSD_BUS_WIDTH        183    /* R/W */
>>>> +#define EXT_CSD_STROBE_SUPPORT        184    /* RO */
>>>>    #define EXT_CSD_HS_TIMING        185    /* R/W */
>>>>    #define EXT_CSD_POWER_CLASS        187    /* R/W */
>>>>    #define EXT_CSD_REV            192    /* RO */
>>>> @@ -380,12 +381,14 @@ struct _mmc_csd {
>>>>    #define EXT_CSD_CARD_TYPE_HS400_1_2V    (1<<7)    /* Card can run at 200MHz DDR, 1.2V */
>>>>    #define EXT_CSD_CARD_TYPE_HS400        (EXT_CSD_CARD_TYPE_HS400_1_8V | \
>>>>                         EXT_CSD_CARD_TYPE_HS400_1_2V)
>>>> +#define EXT_CSD_CARD_TYPE_HS400ES    (1<<8)    /* Card can run at HS400ES */
>>>>
>>>>    #define EXT_CSD_BUS_WIDTH_1    0    /* Card is in 1 bit mode */
>>>>    #define EXT_CSD_BUS_WIDTH_4    1    /* Card is in 4 bit mode */
>>>>    #define EXT_CSD_BUS_WIDTH_8    2    /* Card is in 8 bit mode */
>>>>    #define EXT_CSD_DDR_BUS_WIDTH_4    5    /* Card is in 4 bit DDR mode */
>>>>    #define EXT_CSD_DDR_BUS_WIDTH_8    6    /* Card is in 8 bit DDR mode */
>>>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)    /* Enhanced strobe mode */
>>>>
>>>>    #define EXT_CSD_TIMING_BC    0    /* Backwards compatility */
>>>>    #define EXT_CSD_TIMING_HS    1    /* High speed */
>>>>
>>>
>>>
>>>
>>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>>
>
>
>
>



From shawn.lin at rock-chips.com  Fri May 20 01:34:45 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 16:34:45 +0800
Subject: [PATCH v4 0/5] Add enhanced strobe support for emmc version 5.1 or
 later
Message-ID: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>


Hello all,

This patch is going to support enhanced strobe function
for emmc version 5.1+ introduced by JEDEC recently.

Enchanced strobe is a optional function, so we add a new cap* for drivers to
decide whether to use it.

When introduing hs400 mode, JEDEC asks controllers to use data strobe line
to latch the data from emmc devives. But for cmd-reponse, not mentioned yet.
Since emmc version 5.1 published, JEDEC adds enhanced strobe function to deal
with cmd-response the same way as data-read. This feature is optional.

>From the spec(section 6.6.2.3), the standard scenario to select HS400 enhanced
strobe mode illustrated like this:
(1) set HS_TIMIMG (Highspeed)
(2) Host change freq to <= 52Mhz
(3) set the bus width to Enhanced strobe and DDR8Bit(CMD6), EXT_CSD[183] = 0x86
instead of 0x80
(4) set HS_TIMING to 0x3 (HS400)
(5) Host change freq to <= 200Mhz
(6) Host select HS400 enhanced strobe complete

I can't find a upstreamed controller claimed to support it, as well as the
mmc stack. But my "arasan,sdhci-5.1" actually supports this function. So I decide
to work for this part.

By looking into the SDHCI spec, I find there isn't any registers to enable the
enhanced strobe function. But from my "arasan,sdhci-5.1" databook, it describes a
register called VENDOR_REGISTER(0x78) to trigger this mode. So I guess other sdhci
variant drivers may also need s vendor specific register to deal with it.

If we are sure that our controller supports enhanced strobe mode, just add
mmc-hs400-enhanced-strobe in DT. Once emmc devices claims to support this mode,
we enable it automatically. Of course, other sdhci*/non-sdhci drivers should
implement/overwrite the prepare_enhanced_strobe by themselves. I believe all of the
platforms which need to support this mode should do some basic preparation for their
controllers. Currently I just limit the callback within ths scope of arasan,sdhci-5.1,
but I prone to believe arasan will use VENDOR_REGISTER to tirgger this mode from now on
because I do believe vendor will consider the registers' compatibility.

With this patchset applied, we can successfully run in HS400 enhanced strobe mode on
RK3399 platform with Samsung eMMC KLMBG2JENB-B041(v5.1, 16GB).

mmc1: new HS400 Enhanced strobe MMC card at address 0001
mmcblk0: mmc1:0001 AJNB4R 14.6 GiB
mmcblk0boot0: mmc1:0001 AJNB4R partition 1 4.00 MiB
mmcblk0boot1: mmc1:0001 AJNB4R partition 2 4.00 MiB
mmcblk0rpmb: mmc1:0001 AJNB4R partition 3 4.00 MiB

Also I check this patchset with removing some caps to make sure
all the init sequences for hs400/hs200/DDR52/HighSpeed is correct.


Changes in v4:
- check avail_type with EXT_CSD_CARD_TYPE_HS400 instead of
  card_type
- check if host support 8-bit when selecting hs400es
- some minor fix suggested by Douglas and add his review tag

Changes in v3:
- remove helper function and shorten cap2 to MMC_CAP2_HS400_ES
- rename callback to hs400_enhanced_strobe and make it return void
- add enhanced_strobe in mmc_ios and pass it to hs400_enhanced_strobe
- disable host's enhanced strobe in mmc_set_initial_state
- remove bus checking after switching hs400es
- add new function for hs400es timing selection
- fix wrong judgement of mmc_card_hs400es

Changes in v2:
- switch to HS400ES from Highspeed mode directly

Shawn Lin (5):
  Documentation: mmc: add mmc-hs400-enhanced-strobe
  mmc: core: add mmc-hs400-enhanced-strobe support
  mmc: core: implement enhanced strobe support
  mmc: debugfs: add HS400 enhanced strobe description
  mmc: sdhci-of-arasan: implement enhanced strobe callback

 Documentation/devicetree/bindings/mmc/mmc.txt |  1 +
 drivers/mmc/core/bus.c                        |  3 +-
 drivers/mmc/core/core.c                       |  8 +++
 drivers/mmc/core/debugfs.c                    |  4 +-
 drivers/mmc/core/host.c                       |  2 +
 drivers/mmc/core/mmc.c                        | 84 ++++++++++++++++++++++++++-
 drivers/mmc/host/sdhci-of-arasan.c            | 20 +++++++
 include/linux/mmc/card.h                      |  1 +
 include/linux/mmc/host.h                      | 12 ++++
 include/linux/mmc/mmc.h                       |  3 +
 10 files changed, 134 insertions(+), 4 deletions(-)

-- 
2.3.7




From shawn.lin at rock-chips.com  Fri May 20 01:35:41 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 16:35:41 +0800
Subject: [PATCH v4 1/5] Documentation: mmc: add mmc-hs400-enhanced-strobe
In-Reply-To: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463733341-819-1-git-send-email-shawn.lin@rock-chips.com>

mmc-hs400-enhanced-strobe is used to claim that the
host can support hs400 mode with enhanced strobe
introduced by emmc 5.1 spec.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
Acked-by: Rob Herring <robh at kernel.org>
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 Documentation/devicetree/bindings/mmc/mmc.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index ed23b9b..ecc007a 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -46,6 +46,7 @@ Optional properties:
 - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
 - mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
 - mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
+- mmc-hs400-enhanced-strobe: eMMC HS400 enhanced strobe mode is supported
 - dsr: Value the card's (optional) Driver Stage Register (DSR) should be
   programmed with. Valid range: [0 .. 0xffff].
 
-- 
2.3.7




From shawn.lin at rock-chips.com  Fri May 20 01:35:50 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 16:35:50 +0800
Subject: [PATCH v4 2/5] mmc: core: add mmc-hs400-enhanced-strobe support
In-Reply-To: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463733350-861-1-git-send-email-shawn.lin@rock-chips.com>

This patch introduce mmc-hs400-enhanced-strobe for platforms
which want to enable enhanced strobe function from DT if the
mmc host controller claims to support enhanced strobe.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

---

Changes in v4:
- check avail_type with EXT_CSD_CARD_TYPE_HS400 instead of
  card_type
- check if host support 8-bit when selecting hs400es
- some minor fix suggested by Douglas and add his review tag

Changes in v3:
- remove helper function and shorten cap2 to MMC_CAP2_HS400_ES
- rename callback to hs400_enhanced_strobe and make it return void
- add enhanced_strobe in mmc_ios and pass it to hs400_enhanced_strobe
- disable host's enhanced strobe in mmc_set_initial_state
- remove bus checking after switching hs400es
- add new function for hs400es timing selection
- fix wrong judgement of mmc_card_hs400es

Changes in v2:
- switch to HS400ES from Highspeed mode directly

 drivers/mmc/core/host.c  | 2 ++
 include/linux/mmc/host.h | 1 +
 2 files changed, 3 insertions(+)

diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index e0a3ee1..45773e4 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -289,6 +289,8 @@ int mmc_of_parse(struct mmc_host *host)
 		host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
 	if (of_property_read_bool(np, "mmc-hs400-1_2v"))
 		host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
+	if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
+		host->caps2 |= MMC_CAP2_HS400_ES;
 
 	host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
 	if (host->dsr_req && (host->dsr & ~0xffff)) {
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 85800b4..2a06fb0 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -302,6 +302,7 @@ struct mmc_host {
 #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
 #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18)	/* No physical write protect pin, assume that card is always read-write */
 #define MMC_CAP2_NO_SDIO	(1 << 19)	/* Do not send SDIO commands during initialization */
+#define MMC_CAP2_HS400_ES	(1 << 20)	/* Host supports enhanced strobe */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
-- 
2.3.7




From shawn.lin at rock-chips.com  Fri May 20 01:36:00 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 16:36:00 +0800
Subject: [PATCH v4 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463733360-902-1-git-send-email-shawn.lin@rock-chips.com>

Controllers use data strobe line to latch data from devices
under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
introduces enhanced strobe mode for latching cmd response from
emmc devices to host controllers. This new feature is optional,
so it depends both on device's cap and host's cap to decide
whether to use it or not.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/mmc/core/bus.c   |  3 +-
 drivers/mmc/core/core.c  |  8 +++++
 drivers/mmc/core/mmc.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/mmc/card.h |  1 +
 include/linux/mmc/host.h | 11 +++++++
 include/linux/mmc/mmc.h  |  3 ++
 6 files changed, 107 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 4bc48f1..c64266f 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
-		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
+		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
 			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
+			mmc_card_hs400es(card) ? "Enhanced strobe " : "",
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 99275e4..a559501 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1127,6 +1127,14 @@ void mmc_set_initial_state(struct mmc_host *host)
 	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ios.timing = MMC_TIMING_LEGACY;
 	host->ios.drv_type = 0;
+	host->ios.enhanced_strobe = false;
+
+	/*
+	 * Make sure we are in non-enhanced strobe mode before we
+	 * actually enable it in ext_csd.
+	 */
+	if (host->ops->hs400_enhanced_strobe)
+		host->ops->hs400_enhanced_strobe(host, &host->ios);
 
 	mmc_set_ios(host);
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f99c47e..9dc91ba 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
 	}
 
+	if ((caps2 & MMC_CAP2_HS400_ES) &&
+	    card->ext_csd.strobe_support &&
+	    (avail_type & EXT_CSD_CARD_TYPE_HS400))
+		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			mmc_card_set_blockaddr(card);
 	}
 
+	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
 	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
 	mmc_select_card_type(card);
 
@@ -1216,6 +1222,78 @@ out_err:
 	return err;
 }
 
+static int mmc_select_hs400es(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+	u8 val;
+
+	if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
+		err = -ENOTSUPP;
+		goto out_err;
+	}
+
+	err = mmc_select_bus_width(card);
+	if (IS_ERR_VALUE(err))
+		goto out_err;
+
+	/* Switch card to HS mode */
+	err = mmc_select_hs(card);
+	if (err) {
+		pr_err("%s: switch to high-speed failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	err = mmc_switch_status(card);
+	if (err)
+		goto out_err;
+
+	/* Switch card to DDR with strobe bit */
+	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 val,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	/* Switch card to HS400 */
+	val = EXT_CSD_TIMING_HS400 |
+	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, val,
+			   card->ext_csd.generic_cmd6_time,
+			   true, false, true);
+	if (err) {
+		pr_err("%s: switch to hs400es failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	/* Set host controller to HS400 timing and frequency */
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+
+	/* Controller enable enhanced strobe function */
+	host->ios.enhanced_strobe = true;
+	if (host->ops->hs400_enhanced_strobe)
+		host->ops->hs400_enhanced_strobe(host, &host->ios);
+
+	err = mmc_switch_status(card);
+	if (err)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
+	       __func__, err);
+	return err;
+}
+
 static void mmc_select_driver_type(struct mmc_card *card)
 {
 	int card_drv_type, drive_strength, drv_type;
@@ -1297,7 +1375,7 @@ err:
 }
 
 /*
- * Activate High Speed or HS200 mode if supported.
+ * Activate High Speed, HS200 or HS400ES mode if supported.
  */
 static int mmc_select_timing(struct mmc_card *card)
 {
@@ -1306,7 +1384,9 @@ static int mmc_select_timing(struct mmc_card *card)
 	if (!mmc_can_ext_csd(card))
 		goto bus_speed;
 
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
+		err = mmc_select_hs400es(card);
+	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 		err = mmc_select_hs200(card);
 	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 		err = mmc_select_hs(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index eb0151b..22defc2 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -95,6 +95,7 @@ struct mmc_ext_csd {
 	u8			raw_partition_support;	/* 160 */
 	u8			raw_rpmb_size_mult;	/* 168 */
 	u8			raw_erased_mem_count;	/* 181 */
+	u8			strobe_support;		/* 184 */
 	u8			raw_ext_csd_structure;	/* 194 */
 	u8			raw_card_type;		/* 196 */
 	u8			raw_driver_strength;	/* 197 */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2a06fb0..0eabb72 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -19,6 +19,7 @@
 
 #include <linux/mmc/core.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -77,6 +78,8 @@ struct mmc_ios {
 #define MMC_SET_DRIVER_TYPE_A	1
 #define MMC_SET_DRIVER_TYPE_C	2
 #define MMC_SET_DRIVER_TYPE_D	3
+
+	bool enhanced_strobe;			/* hs400es selection */
 };
 
 struct mmc_host_ops {
@@ -143,6 +146,9 @@ struct mmc_host_ops {
 
 	/* Prepare HS400 target operating frequency depending host driver */
 	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
+	/* Prepare enhanced strobe depending host driver */
+	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
+					 struct mmc_ios *ios);
 	int	(*select_drive_strength)(struct mmc_card *card,
 					 unsigned int max_dtr, int host_drv,
 					 int card_drv, int *drv_type);
@@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
 	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
 }
 
+static inline bool mmc_card_hs400es(struct mmc_card *card)
+{
+	return card->host->ios.enhanced_strobe;
+}
+
 void mmc_retune_timer_stop(struct mmc_host *host);
 
 static inline void mmc_retune_needed(struct mmc_host *host)
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 15f2c4a..c376209 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -297,6 +297,7 @@ struct _mmc_csd {
 #define EXT_CSD_PART_CONFIG		179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
+#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
 #define EXT_CSD_POWER_CLASS		187	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
@@ -380,12 +381,14 @@ struct _mmc_csd {
 #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
 #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
 					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
 #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
 #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
+#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
 
 #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
 #define EXT_CSD_TIMING_HS	1	/* High speed */
-- 
2.3.7




From shawn.lin at rock-chips.com  Fri May 20 01:36:08 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 16:36:08 +0800
Subject: [PATCH v4 4/5] mmc: debugfs: add HS400 enhanced strobe description
In-Reply-To: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463733368-943-1-git-send-email-shawn.lin@rock-chips.com>

We introduce HS400 with enhanced strobe function, so we need
to add it for debug show.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/mmc/core/debugfs.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 9382a57..51d7c38 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -148,7 +148,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc HS200";
 		break;
 	case MMC_TIMING_MMC_HS400:
-		str = "mmc HS400";
+		mmc_card_hs400es(host->card) ?
+			(str = "mmc HS400 enhanced strobe") :
+			(str = "mmc HS400");
 		break;
 	default:
 		str = "invalid";
-- 
2.3.7




From shawn.lin at rock-chips.com  Fri May 20 01:36:17 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 16:36:17 +0800
Subject: [PATCH v4 5/5] mmc: sdhci-of-arasan: implement enhanced strobe
 callback
In-Reply-To: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463733377-986-1-git-send-email-shawn.lin@rock-chips.com>

Currently sdhci-arasan 5.1 can support enhanced strobe function,
and we now limit it just for "arasan,sdhci-5.1". Add
mmc-hs400-enhanced-strobe in DT to enable the function if we're
sure our controller can support it.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
Reviewed-by: Doug Anderson <dianders at chromium.org>
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/mmc/host/sdhci-of-arasan.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index b6f4c1d..533e2bc 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -25,7 +25,9 @@
 #include "sdhci-pltfm.h"
 
 #define SDHCI_ARASAN_CLK_CTRL_OFFSET	0x2c
+#define SDHCI_ARASAN_VENDOR_REGISTER	0x78
 
+#define VENDOR_ENHANCED_STROBE		BIT(0)
 #define CLK_CTRL_TIMEOUT_SHIFT		16
 #define CLK_CTRL_TIMEOUT_MASK		(0xf << CLK_CTRL_TIMEOUT_SHIFT)
 #define CLK_CTRL_TIMEOUT_MIN_EXP	13
@@ -79,6 +81,21 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
 	}
 }
 
+static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
+					struct mmc_ios *ios)
+{
+	u32 vendor;
+	struct sdhci_host *host = mmc_priv(mmc);
+
+	vendor = readl(host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
+	if (ios->enhanced_strobe)
+		vendor |= VENDOR_ENHANCED_STROBE;
+	else
+		vendor &= ~VENDOR_ENHANCED_STROBE;
+
+	writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
+}
+
 static struct sdhci_ops sdhci_arasan_ops = {
 	.set_clock = sdhci_arasan_set_clock,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
@@ -245,6 +262,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev, "phy_power_on err.\n");
 			goto err_phy_power;
 		}
+
+		host->mmc_host_ops.hs400_enhanced_strobe =
+					sdhci_arasan_hs400_enhanced_strobe;
 	}
 
 	ret = sdhci_add_host(host);
-- 
2.3.7




From adrian.hunter at intel.com  Fri May 20 02:58:56 2016
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Fri, 20 May 2016 12:58:56 +0300
Subject: [PATCH v4 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <1463733360-902-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
 <1463733360-902-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <573EDFE0.6000600@intel.com>

On 20/05/16 11:36, Shawn Lin wrote:
> Controllers use data strobe line to latch data from devices
> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
> introduces enhanced strobe mode for latching cmd response from
> emmc devices to host controllers. This new feature is optional,
> so it depends both on device's cap and host's cap to decide
> whether to use it or not.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
> 
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/mmc/core/bus.c   |  3 +-
>  drivers/mmc/core/core.c  |  8 +++++
>  drivers/mmc/core/mmc.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
>  include/linux/mmc/card.h |  1 +
>  include/linux/mmc/host.h | 11 +++++++
>  include/linux/mmc/mmc.h  |  3 ++
>  6 files changed, 107 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index 4bc48f1..c64266f 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			type);
>  	} else {
> -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>  			mmc_hostname(card->host),
>  			mmc_card_uhs(card) ? "ultra high speed " :
>  			(mmc_card_hs(card) ? "high speed " : ""),
>  			mmc_card_hs400(card) ? "HS400 " :
>  			(mmc_card_hs200(card) ? "HS200 " : ""),
> +			mmc_card_hs400es(card) ? "Enhanced strobe " : "",
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			uhs_bus_speed_mode, type, card->rca);
>  	}
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 99275e4..a559501 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -1127,6 +1127,14 @@ void mmc_set_initial_state(struct mmc_host *host)
>  	host->ios.bus_width = MMC_BUS_WIDTH_1;
>  	host->ios.timing = MMC_TIMING_LEGACY;
>  	host->ios.drv_type = 0;
> +	host->ios.enhanced_strobe = false;
> +
> +	/*
> +	 * Make sure we are in non-enhanced strobe mode before we
> +	 * actually enable it in ext_csd.
> +	 */
> +	if (host->ops->hs400_enhanced_strobe)
> +		host->ops->hs400_enhanced_strobe(host, &host->ios);

We probably shouldn't call hs400_enhanced_strobe() if the host controller
driver hasn't set MMC_CAP2_HS400_ES.

>  
>  	mmc_set_ios(host);
>  }
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index f99c47e..9dc91ba 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>  		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>  	}
>  
> +	if ((caps2 & MMC_CAP2_HS400_ES) &&
> +	    card->ext_csd.strobe_support &&
> +	    (avail_type & EXT_CSD_CARD_TYPE_HS400))
> +		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
> +
>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>  	card->mmc_avail_type = avail_type;
> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>  			mmc_card_set_blockaddr(card);
>  	}
>  
> +	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>  	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>  	mmc_select_card_type(card);
>  
> @@ -1216,6 +1222,78 @@ out_err:
>  	return err;
>  }
>  
> +static int mmc_select_hs400es(struct mmc_card *card)
> +{
> +	struct mmc_host *host = card->host;
> +	int err = 0;
> +	u8 val;
> +
> +	if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
> +		err = -ENOTSUPP;
> +		goto out_err;
> +	}
> +
> +	err = mmc_select_bus_width(card);
> +	if (IS_ERR_VALUE(err))
> +		goto out_err;
> +
> +	/* Switch card to HS mode */
> +	err = mmc_select_hs(card);
> +	if (err) {
> +		pr_err("%s: switch to high-speed failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
> +
> +	/* Switch card to DDR with strobe bit */
> +	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			 EXT_CSD_BUS_WIDTH,
> +			 val,
> +			 card->ext_csd.generic_cmd6_time);
> +	if (err) {
> +		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	/* Switch card to HS400 */
> +	val = EXT_CSD_TIMING_HS400 |
> +	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
> +	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			   EXT_CSD_HS_TIMING, val,
> +			   card->ext_csd.generic_cmd6_time,
> +			   true, false, true);
> +	if (err) {
> +		pr_err("%s: switch to hs400es failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	/* Set host controller to HS400 timing and frequency */
> +	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> +
> +	/* Controller enable enhanced strobe function */
> +	host->ios.enhanced_strobe = true;
> +	if (host->ops->hs400_enhanced_strobe)
> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
> +
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
> +
> +	return 0;
> +
> +out_err:
> +	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
> +	       __func__, err);
> +	return err;
> +}
> +
>  static void mmc_select_driver_type(struct mmc_card *card)
>  {
>  	int card_drv_type, drive_strength, drv_type;
> @@ -1297,7 +1375,7 @@ err:
>  }
>  
>  /*
> - * Activate High Speed or HS200 mode if supported.
> + * Activate High Speed, HS200 or HS400ES mode if supported.
>   */
>  static int mmc_select_timing(struct mmc_card *card)
>  {
> @@ -1306,7 +1384,9 @@ static int mmc_select_timing(struct mmc_card *card)
>  	if (!mmc_can_ext_csd(card))
>  		goto bus_speed;
>  
> -	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
> +		err = mmc_select_hs400es(card);
> +	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>  		err = mmc_select_hs200(card);
>  	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>  		err = mmc_select_hs(card);
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index eb0151b..22defc2 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>  	u8			raw_partition_support;	/* 160 */
>  	u8			raw_rpmb_size_mult;	/* 168 */
>  	u8			raw_erased_mem_count;	/* 181 */
> +	u8			strobe_support;		/* 184 */
>  	u8			raw_ext_csd_structure;	/* 194 */
>  	u8			raw_card_type;		/* 196 */
>  	u8			raw_driver_strength;	/* 197 */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 2a06fb0..0eabb72 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -19,6 +19,7 @@
>  
>  #include <linux/mmc/core.h>
>  #include <linux/mmc/card.h>
> +#include <linux/mmc/mmc.h>
>  #include <linux/mmc/pm.h>
>  
>  struct mmc_ios {
> @@ -77,6 +78,8 @@ struct mmc_ios {
>  #define MMC_SET_DRIVER_TYPE_A	1
>  #define MMC_SET_DRIVER_TYPE_C	2
>  #define MMC_SET_DRIVER_TYPE_D	3
> +
> +	bool enhanced_strobe;			/* hs400es selection */
>  };
>  
>  struct mmc_host_ops {
> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>  
>  	/* Prepare HS400 target operating frequency depending host driver */
>  	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
> +	/* Prepare enhanced strobe depending host driver */
> +	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
> +					 struct mmc_ios *ios);
>  	int	(*select_drive_strength)(struct mmc_card *card,
>  					 unsigned int max_dtr, int host_drv,
>  					 int card_drv, int *drv_type);
> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>  	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>  }
>  
> +static inline bool mmc_card_hs400es(struct mmc_card *card)
> +{
> +	return card->host->ios.enhanced_strobe;
> +}
> +
>  void mmc_retune_timer_stop(struct mmc_host *host);
>  
>  static inline void mmc_retune_needed(struct mmc_host *host)
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 15f2c4a..c376209 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -297,6 +297,7 @@ struct _mmc_csd {
>  #define EXT_CSD_PART_CONFIG		179	/* R/W */
>  #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
>  #define EXT_CSD_BUS_WIDTH		183	/* R/W */
> +#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
>  #define EXT_CSD_HS_TIMING		185	/* R/W */
>  #define EXT_CSD_POWER_CLASS		187	/* R/W */
>  #define EXT_CSD_REV			192	/* RO */
> @@ -380,12 +381,14 @@ struct _mmc_csd {
>  #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
>  #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
>  					 EXT_CSD_CARD_TYPE_HS400_1_2V)
> +#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
>  
>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
>  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
>  
>  #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
>  #define EXT_CSD_TIMING_HS	1	/* High speed */
> 



From shawn.lin at rock-chips.com  Fri May 20 03:28:25 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 18:28:25 +0800
Subject: [PATCH 0/2] Add Rockchip PCIe RC controller support
Message-ID: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>


Hi all,

This patchset gonna support Rockchip PCIe controller integrated
in RK3399 Soc supporting Gen2 with max 4 lanes.

Also it supports:
(1) Support Single-root I/O virtualization(SR-IOV)
(2) Support Legacy Interrupt
(3) Support MSI and MSI-X interrupt
(4) Support ECRC Generation and Checking
(5) Support 8 Virtual Functions attached to Physical Function
(6) Support Outbound and Inbound address translation
(7) Support ASPM state L0s and L1
(8) Support L1 Power Management Substate
(9) Support PCI Function power states D0, D1 and D3, and the corresponding
link power states L0, L1 and L2


Please review, test and comment. Thanks.



Shawn Lin (2):
  Documentation: add binding description of Rockchip PCIe controller
  pci: Add PCIe driver for Rockchip Soc

 .../devicetree/bindings/pci/rockchip-pcie.txt      |   93 ++
 drivers/pci/host/Kconfig                           |   12 +
 drivers/pci/host/Makefile                          |    1 +
 drivers/pci/host/pcie-rockchip.c                   | 1181 ++++++++++++++++++++
 4 files changed, 1287 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/rockchip-pcie.txt
 create mode 100644 drivers/pci/host/pcie-rockchip.c

-- 
2.3.7




From shawn.lin at rock-chips.com  Fri May 20 03:29:06 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 18:29:06 +0800
Subject: [PATCH 1/2] Documentation: add binding description of Rockchip PCIe
 controller
In-Reply-To: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463740146-7106-1-git-send-email-shawn.lin@rock-chips.com>

This patch add some required and optional properties for Rockchip
PCIe controller. Also we add a example for how to use it.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

---

 .../devicetree/bindings/pci/rockchip-pcie.txt      | 93 ++++++++++++++++++++++
 1 file changed, 93 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/pci/rockchip-pcie.txt

diff --git a/Documentation/devicetree/bindings/pci/rockchip-pcie.txt b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
new file mode 100644
index 0000000..69a0804
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
@@ -0,0 +1,93 @@
+* Rockchip AXI PCIe Root Port Bridge DT description
+
+Required properties:
+- #address-cells: Address representation for root ports, set to <3>
+- #size-cells: Size representation for root ports, set to <2>
+- #interrupt-cells: specifies the number of cells needed to encode an
+		interrupt source. The value must be 1.
+- compatible: Should contain "rockchip,rk3399-pcie"
+- reg: Two register ranges as listed in the reg-names property
+- reg-names: The first entry must be "axi-base" for the core registers
+	The second entry must be "apb-base" for the client pcie registers
+- clocks: Must contain an entry for each entry in clock-names.
+		See ../clocks/clock-bindings.txt for details.
+- clock-names: Must include the following entries:
+	- "aclk_pcie"
+	- "aclk_perf_pcie"
+	- "hclk_pcie"
+	- "clk_pciephy_ref"
+- interrupts: Three interrupt entries must be specified.
+- interrupt-names: Must include the following names
+	- "pcie-sys"
+	- "pcie-legacy"
+	- "pcie-client"
+- resets: Must contain five entries for each entry in reset-names.
+	   See ../reset/reset.txt for details.
+- reset-names: Must include the following names
+	- "phy-rst"
+	- "core-rst"
+	- "mgmt-rst"
+	- "mgmt-sticky-rst"
+	- "pipe-rst"
+- rockchip,grf: phandle to the syscon managing the "general register files"
+- pcie-conf: offset of pcie client block for  configuration
+- pcie-status: offset of pcie client block for status
+- pcie-laneoff: offset of pcie client block for lane
+- msi-parent: Link to the hardware entity that serves as the Message
+- pinctrl-names : The pin control state names
+- pinctrl-0: The "default" pinctrl state
+- interrupt-map-mask and interrupt-map: standard PCI properties
+- interrupt-controller: identifies the node as an interrupt controller
+
+Optional Property:
+- ep-gpios: contain the entry for pre-reset gpio
+- num-lanes: number of lanes to use
+- assigned-clocks, assigned-clock-parents and assigned-clock-rates: standard
+		   clock bindings. See ../clock/clock-bindings.txt
+
+Example:
+
+pci_express: axi-pcie at f8000000 {
+	#address-cells = <3>;
+	#size-cells = <2>;
+	compatible = "rockchip,rk3399-pcie";
+	clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>,
+		 <&cru PCLK_PCIE>, <&cru SCLK_PCIEPHY_REF>;
+	clock-names = "aclk_pcie", "aclk_perf_pcie",
+		      "hclk_pcie", "clk_pciephy_ref";
+	bus-range = <0x0 0x1>;
+	interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>,
+		     <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+	interrupt-names: "pcie-sys", "pcie-legacy", "pcie-client";
+	assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
+	assigned-clock-parents = <&cru SCLK_PCIEPHY_REF100M>;
+	assigned-clock-rates = <100000000>;
+	ep-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
+	ranges = < 0x82000000 0 0xfa000000 0x0 0xfa000000 0 0x600000
+		   0x81000000 0 0xfa600000 0x0 0xfa600000 0 0x100000 >;
+	num-lanes = <4>;
+	reg = < 0x0 0xf8000000 0x0 0x2000000 >, < 0x0 0xfd000000 0x0 0x1000000 >;
+	reg-name = "axi-base", "apb-base";
+	resets = <&cru SRST_PCIEPHY>, <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>,
+		 <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>;
+	reset-names = "phy-rst", "core-rst", "mgmt-rst", "mgmt-sticky-rst", "pipe-rst";
+	rockchip,grf = <&grf>;
+	pcie-conf = <0xe220>;
+	pcie-status = <0xe2a4>;
+	pcie-laneoff = <0xe214>;
+	pinctrl-names = "default";
+	pinctrl-0 = <&pcie_clkreq>;
+	msi-parent = <&its>;
+	#interrupt-cells = <1>;
+	interrupt-map-mask = <0 0 0 7>;
+	interrupt-map = <0 0 0 1 &pcie_0 1>,
+			<0 0 0 2 &pcie_0 2>,
+			<0 0 0 3 &pcie_0 3>,
+			<0 0 0 4 &pcie_0 4>;
+	pcie_0: interrupt-controller {
+		interrupt-controller;
+		#address-cells = <0>;
+		#interrupt-cells = <1>;
+	};
+
+};
-- 
2.3.7




From shawn.lin at rock-chips.com  Fri May 20 03:29:16 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 18:29:16 +0800
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>

RK3399 has a PCIe controller which can be used as Root Complex.
This driver supports a PCIe controller as Root Complex mode.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

 drivers/pci/host/Kconfig         |   12 +
 drivers/pci/host/Makefile        |    1 +
 drivers/pci/host/pcie-rockchip.c | 1181 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 1194 insertions(+)
 create mode 100644 drivers/pci/host/pcie-rockchip.c

diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 8e4f038..76447a8 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -245,4 +245,16 @@ config PCIE_ARMADA_8K
 	  Designware hardware and therefore the driver re-uses the
 	  Designware core functions to implement the driver.
 
+config PCIE_ROCKCHIP
+	bool "Rockchip PCIe controller"
+	depends on ARM64 && ARCH_ROCKCHIP
+	depends on OF
+	select MFD_SYSCON
+	select PCI_MSI
+	select PCI_MSI_IRQ_DOMAIN
+	help
+	  Say Y here if you want internal PCI support on Rockchip SoC.
+	  There are 1 internal PCIe port available to support GEN2 with
+	  4 slots.
+
 endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index a6f85e3..fb3871e 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
 obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
 obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
 obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
+obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
new file mode 100644
index 0000000..4063fd3
--- /dev/null
+++ b/drivers/pci/host/pcie-rockchip.c
@@ -0,0 +1,1181 @@
+/*
+ * Rockchip AXI PCIe host controller driver
+ *
+ * Copyright (c) 2016 Rockchip, Inc.
+ *
+ * Author: Shawn Lin <shawn.lin at rock-chips.com>
+ *         Wenrui Li <wenrui.li at rock-chips.com>
+ * Bits taken from Synopsys Designware Host controller driver and
+ * ARM PCI Host generic driver.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/kernel.h>
+#include <linux/mfd/syscon.h>
+#include <linux/module.h>
+#include <linux/msi.h>
+#include <linux/of_address.h>
+#include <linux/of_device.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+
+#define REF_CLK_100MHZ			(100 * 1000 * 1000)
+#define PCIE_CLIENT_BASE		0x0
+#define PCIE_RC_CONFIG_BASE		0xa00000
+#define PCIE_CORE_CTRL_MGMT_BASE	0x900000
+#define PCIE_CORE_AXI_CONF_BASE		0xc00000
+#define PCIE_CORE_AXI_INBOUND_BASE	0xc00800
+
+#define PCIE_CLIENT_BASIC_STATUS0	0x44
+#define PCIE_CLIENT_BASIC_STATUS1	0x48
+#define PCIE_CLIENT_INT_MASK		0x4c
+#define PCIE_CLIENT_INT_STATUS		0x50
+#define PCIE_CORE_INT_MASK		0x900210
+#define PCIE_CORE_INT_STATUS		0x90020c
+
+/** Size of one AXI Region (not Region 0) */
+#define	AXI_REGION_SIZE			(0x1 << 20)
+/** Overall size of AXI area */
+#define	AXI_OVERALL_SIZE		(64 * (0x1 << 20))
+/** Size of Region 0, equal to sum of sizes of other regions */
+#define	AXI_REGION_0_SIZE		(32 * (0x1 << 20))
+#define OB_REG_SIZE_SHIFT		5
+#define IB_ROOT_PORT_REG_SIZE_SHIFT	3
+
+#define AXI_WRAPPER_IO_WRITE		0x6
+#define AXI_WRAPPER_MEM_WRITE		0x2
+#define MAX_AXI_IB_ROOTPORT_REGION_NUM	3
+#define	MIN_AXI_ADDR_BITS_PASSED	8
+
+#define ROCKCHIP_PCIE_RPIFR1_INTR_MASK	GENMASK(8, 5)
+#define ROCKCHIP_PCIE_RPIFR1_INTR_SHIFT	5
+#define CLIENT_INTERRUPTS \
+		(LOC_INT | INTA | INTB | INTC | INTD |\
+		 CORR_ERR | NFATAL_ERR | FATAL_ERR | DPA_INT | \
+		 HOT_RESET | MSG_DONE | LEGACY_DONE)
+#define CORE_INTERRUPTS	\
+		(PRFPE | CRFPE | RRPE | CRFO | RT | RTR | \
+		 PE | MTR | UCR | FCE | CT | UTC | MMVC)
+#define PWR_STCG			BIT(0)
+#define HOT_PLUG			BIT(1)
+#define PHY_INT				BIT(2)
+#define UDMA_INT			BIT(3)
+#define LOC_INT				BIT(4)
+#define INTA				BIT(5)
+#define INTB				BIT(6)
+#define INTC				BIT(7)
+#define INTD				BIT(8)
+#define CORR_ERR			BIT(9)
+#define NFATAL_ERR			BIT(10)
+#define FATAL_ERR			BIT(11)
+#define DPA_INT				BIT(12)
+#define HOT_RESET			BIT(13)
+#define MSG_DONE			BIT(14)
+#define LEGACY_DONE			BIT(15)
+#define PRFPE				BIT(0)
+#define CRFPE				BIT(1)
+#define RRPE				BIT(2)
+#define PRFO				BIT(3)
+#define CRFO				BIT(4)
+#define RT				BIT(5)
+#define RTR				BIT(6)
+#define PE				BIT(7)
+#define MTR				BIT(8)
+#define UCR				BIT(9)
+#define FCE				BIT(10)
+#define CT				BIT(11)
+#define UTC				BIT(18)
+#define MMVC				BIT(19)
+
+#define PCIE_ECAM_BUS(x)		(((x) & 0xFF) << 20)
+#define PCIE_ECAM_DEV(x)		(((x) & 0x1F) << 15)
+#define PCIE_ECAM_FUNC(x)		(((x) & 0x7) << 12)
+#define PCIE_ECAM_REG(x)		(((x) & 0xFFF) << 0)
+#define PCIE_ECAM_ADDR(bus, dev, func, reg) \
+	  (PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \
+	   PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg))
+
+#define RC_REGION_0_ADDR_TRANS_H	0x00000000
+#define RC_REGION_0_ADDR_TRANS_L	0x00000000
+#define RC_REGION_0_PASS_BITS		(25 - 1)
+#define RC_REGION_1_ADDR_TRANS_H	0x00000000
+#define RC_REGION_1_ADDR_TRANS_L	0x00400000
+#define RC_REGION_1_PASS_BITS		(20 - 1)
+#define MAX_AXI_WRAPPER_REGION_NUM	33
+#define PCIE_CLIENT_CONF_ENABLE		BIT(0)
+#define PCIE_CLIENT_CONF_LANE_NUM(x)	((x / 2) << 4)
+#define PCIE_CLIENT_MODE_RC		BIT(6)
+#define PCIE_CLIENT_GEN_SEL_2		BIT(7)
+#define PCIE_CLIENT_GEN_SEL_1		0x0
+
+struct rockchip_pcie_port {
+	void __iomem *reg_base;
+	void __iomem *apb_base;
+	struct regmap *grf;
+	unsigned int pcie_conf;
+	unsigned int pcie_status;
+	unsigned int pcie_laneoff;
+	struct reset_control *phy_rst;
+	struct reset_control *core_rst;
+	struct reset_control *mgmt_rst;
+	struct reset_control *mgmt_sticky_rst;
+	struct reset_control *pipe_rst;
+	struct clk *aclk_pcie;
+	struct clk *aclk_perf_pcie;
+	struct clk *hclk_pcie;
+	struct clk *clk_pciephy_ref;
+	struct gpio_desc *ep_gpio;
+	u32 lanes;
+	resource_size_t		io_base;
+	struct resource		*cfg;
+	struct resource		*io;
+	struct resource		*mem;
+	struct resource		*busn;
+	phys_addr_t		io_bus_addr;
+	u32			io_size;
+	phys_addr_t		mem_bus_addr;
+	u32			mem_size;
+	u8	root_bus_nr;
+	int irq;
+	struct msi_controller *msi;
+
+	struct device *dev;
+	struct irq_domain *irq_domain;
+};
+
+static inline u32 pcie_read(struct rockchip_pcie_port *port, u32 reg)
+{
+	return readl(port->apb_base + reg);
+}
+
+static inline void pcie_write(struct rockchip_pcie_port *port,
+			      u32 val, u32 reg)
+{
+	writel(val, port->apb_base + reg);
+}
+
+static inline void pcie_pb_wr_cfg(struct rockchip_pcie_port *port,
+				  u32 addr, u32 data)
+{
+	regmap_write(port->grf, port->pcie_conf,
+		     (0x3ff << 17) | (data << 7) | (addr << 1));
+	udelay(1);
+	regmap_write(port->grf, port->pcie_conf,
+		     (0x1 << 16) | (0x1 << 0));
+	udelay(1);
+	regmap_write(port->grf, port->pcie_conf,
+		     (0x1 << 16) | (0x0 << 0));
+}
+
+static inline u32 pcie_pb_rd_cfg(struct rockchip_pcie_port *port,
+				 u32 addr)
+{
+	u32 val;
+
+	regmap_write(port->grf, port->pcie_conf,
+		     (0x3ff << 17) | (addr << 1));
+	regmap_read(port->grf, port->pcie_status, &val);
+	return val;
+}
+
+static int rockchip_pcie_valid_config(struct rockchip_pcie_port *pp,
+				      struct pci_bus *bus, int dev)
+{
+	/* access only one slot on each root port */
+	if (bus->number == pp->root_bus_nr && dev > 0)
+		return 0;
+
+	/*
+	 * do not read more than one device on the bus directly attached
+	 * to RC's (Virtual Bridge's) DS side.
+	 */
+	if (bus->primary == pp->root_bus_nr && dev > 0)
+		return 0;
+
+	return 1;
+}
+
+static int rockchip_pcie_rd_own_conf(struct rockchip_pcie_port *pp,
+				     int where, int size,
+				     u32 *val)
+{
+	void __iomem *addr = pp->apb_base + PCIE_RC_CONFIG_BASE + where;
+
+	if ((uintptr_t)addr & (size - 1)) {
+		*val = 0;
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+
+	if (size == 4) {
+		*val = readl(addr);
+	} else if (size == 2) {
+		*val = readw(addr);
+	} else if (size == 1) {
+		*val = readb(addr);
+	} else {
+		*val = 0;
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int rockchip_pcie_wr_own_conf(struct rockchip_pcie_port *pp,
+				     int where, int size, u32 val)
+{
+	u32 tmp;
+	int offset;
+
+	offset = (where & (~0x3));
+	tmp = readl(pp->apb_base + PCIE_RC_CONFIG_BASE + offset);
+	if (size == 4) {
+		writel(val, pp->apb_base + PCIE_RC_CONFIG_BASE + where);
+	} else if (size == 2) {
+		if (where & 0x2)
+			tmp = ((tmp & 0xffff) | (val << 16));
+		else
+			tmp = ((tmp & 0xffff0000) | val);
+
+		writel(tmp, pp->apb_base + PCIE_RC_CONFIG_BASE + offset);
+	} else if (size == 1) {
+		if ((where & 0x3) == 0)
+			tmp = ((tmp & (~0xff)) | val);
+		else if ((where & 0x3) == 1)
+			tmp = ((tmp & (~0xff00)) | (val << 8));
+		else if ((where & 0x3) == 2)
+			tmp = ((tmp & (~0xff0000)) | (val << 16));
+		else if ((where & 0x3) == 3)
+			tmp = ((tmp & (~0xff000000)) | (val << 24));
+
+		writel(tmp, pp->apb_base + PCIE_RC_CONFIG_BASE + offset);
+	} else {
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int rockchip_pcie_rd_other_conf(struct rockchip_pcie_port *pp,
+				       struct pci_bus *bus, u32 devfn,
+				       int where, int size, u32 *val)
+{
+	u32 busdev;
+
+	busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
+				PCI_FUNC(devfn), where);
+
+	if (busdev & (size - 1)) {
+		*val = 0;
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+
+	if (size == 4) {
+		*val = readl(pp->reg_base + busdev);
+	} else if (size == 2) {
+		*val = readw(pp->reg_base + busdev);
+	} else if (size == 1) {
+		*val = readb(pp->reg_base + busdev);
+	} else {
+		*val = 0;
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+	}
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int rockchip_pcie_wr_other_conf(struct rockchip_pcie_port *pp,
+				       struct pci_bus *bus, u32 devfn,
+				       int where, int size, u32 val)
+{
+	u32 busdev;
+
+	busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
+				PCI_FUNC(devfn), where);
+	if (busdev & (size - 1))
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	if (size == 4)
+		writel(val, pp->reg_base + busdev);
+	else if (size == 2)
+		writew(val, pp->reg_base + busdev);
+	else if (size == 1)
+		writeb(val, pp->reg_base + busdev);
+	else
+		return PCIBIOS_BAD_REGISTER_NUMBER;
+
+	return PCIBIOS_SUCCESSFUL;
+}
+
+static int rockchip_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
+				 int size, u32 *val)
+{
+	struct rockchip_pcie_port *pp = bus->sysdata;
+	int ret;
+
+	if (rockchip_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) {
+		*val = 0xffffffff;
+		return PCIBIOS_DEVICE_NOT_FOUND;
+	}
+
+	if (bus->number != pp->root_bus_nr)
+		ret = rockchip_pcie_rd_other_conf(pp, bus, devfn,
+						  where, size, val);
+	else
+		ret = rockchip_pcie_rd_own_conf(pp, where, size, val);
+
+	return ret;
+}
+
+static int rockchip_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
+				 int where, int size, u32 val)
+{
+	struct rockchip_pcie_port *pp = bus->sysdata;
+	int ret;
+
+	if (rockchip_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
+		return PCIBIOS_DEVICE_NOT_FOUND;
+
+	if (bus->number != pp->root_bus_nr)
+		ret = rockchip_pcie_wr_other_conf(pp, bus, devfn,
+						  where, size, val);
+	else
+		ret = rockchip_pcie_wr_own_conf(pp, where, size, val);
+
+	return ret;
+}
+
+static struct pci_ops rockchip_pcie_ops = {
+	.read = rockchip_pcie_rd_conf,
+	.write = rockchip_pcie_wr_conf,
+};
+
+/**
+ * rockchip_pcie_init_port - Initialize hardware
+ * @port: PCIe port information
+ */
+static int rockchip_pcie_init_port(struct rockchip_pcie_port *port)
+{
+	int err;
+	u32 status;
+	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
+
+	gpiod_set_value(port->ep_gpio, 0);
+
+	/* Make sure PCIe relate block is in reset state */
+	err = reset_control_assert(port->phy_rst);
+	if (err) {
+		dev_err(port->dev, "assert phy_rst err %d\n", err);
+		return err;
+	}
+	err = reset_control_assert(port->core_rst);
+	if (err) {
+		dev_err(port->dev, "assert core_rst err %d\n", err);
+		return err;
+	}
+	err = reset_control_assert(port->mgmt_rst);
+	if (err) {
+		dev_err(port->dev, "assert mgmt_rst err %d\n", err);
+		return err;
+	}
+	err = reset_control_assert(port->mgmt_sticky_rst);
+	if (err) {
+		dev_err(port->dev, "assert mgmt_sticky_rst err %d\n", err);
+		return err;
+	}
+	err = reset_control_assert(port->pipe_rst);
+	if (err) {
+		dev_err(port->dev, "assert pipe_rst err %d\n", err);
+		return err;
+	}
+
+	pcie_write(port, (0xf << 20) | (0x1 << 16) | PCIE_CLIENT_GEN_SEL_2 |
+			  (0x1 << 19) | (0x1 << 3) |
+			  PCIE_CLIENT_MODE_RC |
+			  PCIE_CLIENT_CONF_LANE_NUM(port->lanes) |
+			  PCIE_CLIENT_CONF_ENABLE, PCIE_CLIENT_BASE);
+
+	err = reset_control_deassert(port->phy_rst);
+	if (err) {
+		dev_err(port->dev, "deassert phy_rst err %d\n", err);
+		return err;
+	}
+	regmap_write(port->grf, port->pcie_conf,
+		     (0x3f << 17) | (0x10 << 1));
+	err = -EINVAL;
+	while (time_before(jiffies, timeout)) {
+		regmap_read(port->grf, port->pcie_status, &status);
+		if ((status & (1 << 9))) {
+			dev_info(port->dev, "pll locked!\n");
+			err = 0;
+			break;
+		}
+	}
+	if (err) {
+		dev_err(port->dev, "pll lock timeout!\n");
+		return err;
+	}
+	pcie_pb_wr_cfg(port, 0x10, 0x8);
+	pcie_pb_wr_cfg(port, 0x12, 0x8);
+
+	err = -ETIMEDOUT;
+	while (time_before(jiffies, timeout)) {
+		regmap_read(port->grf, port->pcie_status, &status);
+		if (!(status & (1 << 10))) {
+			dev_info(port->dev, "pll output enable done!\n");
+			err = 0;
+			break;
+		}
+	}
+
+	if (err) {
+		dev_err(port->dev, "pll output enable timeout!\n");
+		return err;
+	}
+
+	regmap_write(port->grf, port->pcie_conf,
+		     (0x3f << 17) | (0x10 << 1));
+	err = -EINVAL;
+	while (time_before(jiffies, timeout)) {
+		regmap_read(port->grf, port->pcie_status, &status);
+		if ((status & (1 << 9))) {
+			dev_info(port->dev, "pll relocked!\n");
+			err = 0;
+			break;
+		}
+	}
+	if (err) {
+		dev_err(port->dev, "pll relock timeout!\n");
+		return err;
+	}
+
+	err = reset_control_deassert(port->core_rst);
+	if (err) {
+		dev_err(port->dev, "deassert core_rst err %d\n", err);
+		return err;
+	}
+	err = reset_control_deassert(port->mgmt_rst);
+	if (err) {
+		dev_err(port->dev, "deassert mgmt_rst err %d\n", err);
+		return err;
+	}
+	err = reset_control_deassert(port->mgmt_sticky_rst);
+	if (err) {
+		dev_err(port->dev, "deassert mgmt_sticky_rst err %d\n", err);
+		return err;
+	}
+	err = reset_control_deassert(port->pipe_rst);
+	if (err) {
+		dev_err(port->dev, "deassert pipe_rst err %d\n", err);
+		return err;
+	}
+
+	pcie_write(port, 1 << 17 | 1 << 1, PCIE_CLIENT_BASE);
+
+	gpiod_set_value(port->ep_gpio, 1);
+	err = -ETIMEDOUT;
+	while (time_before(jiffies, timeout)) {
+		status = pcie_read(port, PCIE_CLIENT_BASIC_STATUS1);
+		if (((status >> 20) & 0x3) == 0x3) {
+			dev_info(port->dev, "pcie link training gen1 pass!\n");
+			err = 0;
+			break;
+		}
+	}
+	if (err) {
+		dev_err(port->dev, "pcie link training gen1 timeout!\n");
+		return err;
+	}
+
+	status = pcie_read(port, 0x9000d0);
+	status |= 0x20;
+	pcie_write(port, status, 0x9000d0);
+	err = -ETIMEDOUT;
+	while (time_before(jiffies, timeout)) {
+		status = pcie_read(port, PCIE_CORE_CTRL_MGMT_BASE);
+		if (((status >> 3) & 0x3) == 0x1) {
+			dev_info(port->dev, "pcie link training gen2 pass!\n");
+			err = 0;
+			break;
+		}
+	}
+	if (err)
+		dev_dbg(port->dev, "pcie link training gen2 timeout, force to gen1!\n");
+
+	if (((status >> 3) & 0x3) == 0x0)
+		dev_info(port->dev, "pcie link 2.5!\n");
+	if (((status >> 3) & 0x3) == 0x1)
+		dev_info(port->dev, "pcie link 5.0!\n");
+
+	status = pcie_read(port, PCIE_CORE_CTRL_MGMT_BASE);
+	status =  0x1 << ((status >> 1) & 0x3);
+	dev_info(port->dev, "current link width is x%d\n", status);
+
+	status = pcie_pb_rd_cfg(port, 0x30);
+	if (!((status >> 11) & 0x1))
+		dev_dbg(port->dev, "lane A is used\n");
+	else
+		regmap_write(port->grf, port->pcie_laneoff,
+			     (0x1 << 19) | (0x1 << 3));
+
+	status = pcie_pb_rd_cfg(port, 0x31);
+	if (!((status >> 11) & 0x1))
+		dev_dbg(port->dev, "lane B is used\n");
+	else
+		regmap_write(port->grf, port->pcie_laneoff,
+			     (0x2 << 19) | (0x2 << 3));
+
+	status = pcie_pb_rd_cfg(port, 0x32);
+	if (!((status >> 11) & 0x1))
+		dev_dbg(port->dev, "lane C is used\n");
+	else
+		regmap_write(port->grf, port->pcie_laneoff,
+			     (0x4 << 19) | (0x4 << 3));
+
+	status = pcie_pb_rd_cfg(port, 0x33);
+	if (!((status >> 11) & 0x1))
+		dev_dbg(port->dev, "lane D is used\n");
+	else
+		regmap_write(port->grf, port->pcie_laneoff,
+			     (0x8 << 19) | (0x8 << 3));
+	return 0;
+}
+
+/**
+ * rockchip_pcie_parse_dt - Parse Device tree
+ * @port: PCIe port information
+ *
+ * Return: '0' on success and error value on failure
+ */
+static int rockchip_pcie_parse_dt(struct rockchip_pcie_port *port)
+{
+	struct device *dev = port->dev;
+	struct device_node *node = dev->of_node;
+	struct resource regs;
+	unsigned int pcie_conf;
+	unsigned int pcie_status;
+	unsigned int pcie_laneoff;
+	int err;
+
+	err = of_address_to_resource(node, 0, &regs);
+	if (err) {
+		dev_err(dev, "missing \"reg\" property\n");
+		return err;
+	}
+
+	port->reg_base = devm_ioremap_resource(dev, &regs);
+	if (IS_ERR(port->reg_base))
+		return PTR_ERR(port->reg_base);
+
+	err = of_address_to_resource(node, 1, &regs);
+	if (err) {
+		dev_err(dev, "missing \"reg\" property\n");
+		return err;
+	}
+
+	port->apb_base = devm_ioremap_resource(dev, &regs);
+	if (IS_ERR(port->apb_base))
+		return PTR_ERR(port->apb_base);
+
+	port->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
+						    "rockchip,grf");
+	if (IS_ERR(port->grf)) {
+		dev_err(dev, "Missing rockchip,grf property\n");
+		return PTR_ERR(port->grf);
+	}
+
+	if (of_property_read_u32(node, "pcie-conf", &pcie_conf)) {
+		dev_err(dev, "missing pcie-conf property in node %s\n",
+			node->name);
+		return -EINVAL;
+	}
+
+	port->pcie_conf = pcie_conf;
+
+	if (of_property_read_u32(node, "pcie-status", &pcie_status)) {
+		dev_err(dev, "missing pcie-status property in node %s\n",
+			node->name);
+		return -EINVAL;
+	}
+
+	port->pcie_status = pcie_status;
+
+	if (of_property_read_u32(node, "pcie-laneoff", &pcie_laneoff)) {
+		dev_err(dev, "missing pcie-laneoff property in node %s\n",
+			node->name);
+		return -EINVAL;
+	}
+
+	port->pcie_laneoff = pcie_laneoff;
+
+	port->lanes = 1;
+	err = of_property_read_u32(node, "num-lanes", &port->lanes);
+	if (!err && ((port->lanes == 0) ||
+		     (port->lanes == 3) ||
+		     (port->lanes > 4))) {
+		dev_info(dev, "invalid num-lanes, default use one lane\n");
+		port->lanes = 1;
+	}
+
+	port->phy_rst = devm_reset_control_get(dev, "phy-rst");
+	if (IS_ERR(port->phy_rst)) {
+		if (PTR_ERR(port->phy_rst) != -EPROBE_DEFER)
+			dev_err(dev, "missing phy-rst property in node %s\n",
+				node->name);
+		err = PTR_ERR(port->phy_rst);
+		goto err_aclk_pcie;
+	}
+
+	port->core_rst = devm_reset_control_get(dev, "core-rst");
+	if (IS_ERR(port->core_rst)) {
+		if (PTR_ERR(port->core_rst) != -EPROBE_DEFER)
+			dev_err(dev, "missing core-rst property in node %s\n",
+				node->name);
+		err = PTR_ERR(port->core_rst);
+		goto err_aclk_pcie;
+	}
+
+	port->mgmt_rst = devm_reset_control_get(dev, "mgmt-rst");
+	if (IS_ERR(port->mgmt_rst)) {
+		if (PTR_ERR(port->mgmt_rst) != -EPROBE_DEFER)
+			dev_err(dev, "missing mgmt-rst property in node %s\n",
+				node->name);
+		err = PTR_ERR(port->mgmt_rst);
+		goto err_aclk_pcie;
+	}
+
+	port->mgmt_sticky_rst = devm_reset_control_get(dev, "mgmt-sticky-rst");
+	if (IS_ERR(port->mgmt_sticky_rst)) {
+		if (PTR_ERR(port->mgmt_sticky_rst) != -EPROBE_DEFER)
+			dev_err(dev, "missing mgmt-sticky-rst property in node %s\n",
+				node->name);
+		err = PTR_ERR(port->mgmt_sticky_rst);
+		goto err_aclk_pcie;
+	}
+
+	port->pipe_rst = devm_reset_control_get(dev, "pipe-rst");
+	if (IS_ERR(port->pipe_rst)) {
+		if (PTR_ERR(port->pipe_rst) != -EPROBE_DEFER)
+			dev_err(dev, "missing pipe-rst property in node %s\n",
+				node->name);
+		err = PTR_ERR(port->pipe_rst);
+		goto err_aclk_pcie;
+	}
+
+	port->ep_gpio = gpiod_get(dev, "ep", GPIOD_OUT_HIGH);
+	if (IS_ERR(port->ep_gpio)) {
+		dev_err(dev, "missing ep-gpios property in node %s\n",
+			node->name);
+		return PTR_ERR(port->ep_gpio);
+	}
+
+	port->aclk_pcie = devm_clk_get(dev, "aclk_pcie");
+	if (IS_ERR(port->aclk_pcie)) {
+		dev_err(dev, "aclk_pcie clock not found.\n");
+		return PTR_ERR(port->aclk_pcie);
+	}
+
+	port->aclk_perf_pcie = devm_clk_get(dev, "aclk_perf_pcie");
+	if (IS_ERR(port->aclk_perf_pcie)) {
+		dev_err(dev, "aclk_perf_pcie clock not found.\n");
+		return PTR_ERR(port->aclk_perf_pcie);
+	}
+
+	port->hclk_pcie = devm_clk_get(dev, "hclk_pcie");
+	if (IS_ERR(port->hclk_pcie)) {
+		dev_err(dev, "hclk_pcie clock not found.\n");
+		return PTR_ERR(port->hclk_pcie);
+	}
+
+	port->clk_pciephy_ref = devm_clk_get(dev, "clk_pciephy_ref");
+	if (IS_ERR(port->clk_pciephy_ref)) {
+		dev_err(dev, "clk_pciephy_ref clock not found.\n");
+		return PTR_ERR(port->clk_pciephy_ref);
+	}
+
+	err = clk_prepare_enable(port->aclk_pcie);
+	if (err) {
+		dev_err(dev, "Unable to enable aclk_pcie clock.\n");
+		goto err_aclk_pcie;
+	}
+
+	err = clk_prepare_enable(port->aclk_perf_pcie);
+	if (err) {
+		dev_err(dev, "Unable to enable aclk_perf_pcie clock.\n");
+		goto err_aclk_perf_pcie;
+	}
+
+	err = clk_prepare_enable(port->hclk_pcie);
+	if (err) {
+		dev_err(dev, "Unable to enable hclk_pcie clock.\n");
+		goto err_hclk_pcie;
+	}
+
+	err = clk_prepare_enable(port->clk_pciephy_ref);
+	if (err) {
+		dev_err(dev, "Unable to enable hclk_pcie clock.\n");
+		goto err_pciephy_ref;
+	}
+
+	return 0;
+
+err_pciephy_ref:
+	clk_disable_unprepare(port->hclk_pcie);
+err_hclk_pcie:
+	clk_disable_unprepare(port->aclk_perf_pcie);
+err_aclk_perf_pcie:
+	clk_disable_unprepare(port->aclk_pcie);
+err_aclk_pcie:
+	return err;
+}
+
+static void rockchip_pcie_msi_enable(struct rockchip_pcie_port *pp)
+{
+	struct device_node *msi_node;
+
+	msi_node = of_parse_phandle(pp->dev->of_node,
+				    "msi-parent", 0);
+	if (!msi_node)
+		return;
+
+	pp->msi = of_pci_find_msi_chip_by_node(msi_node);
+	of_node_put(msi_node);
+
+	if (pp->msi)
+		pp->msi->dev = pp->dev;
+}
+
+static void rockchip_pcie_enable_interrupts(struct rockchip_pcie_port *pp)
+{
+	pcie_write(pp, (CLIENT_INTERRUPTS << 16) &
+		   (~CLIENT_INTERRUPTS), PCIE_CLIENT_INT_MASK);
+	pcie_write(pp, CORE_INTERRUPTS, PCIE_CORE_INT_MASK);
+}
+
+static int rockchip_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
+				  irq_hw_number_t hwirq)
+{
+	irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
+	irq_set_chip_data(irq, domain->host_data);
+
+	return 0;
+}
+
+static const struct irq_domain_ops intx_domain_ops = {
+	.map = rockchip_pcie_intx_map,
+};
+
+static int rockchip_pcie_init_irq_domain(struct rockchip_pcie_port *pp)
+{
+	struct device *dev = pp->dev;
+	struct device_node *node = dev->of_node;
+	struct device_node *pcie_intc_node =  of_get_next_child(node, NULL);
+
+	if (!pcie_intc_node) {
+		dev_err(dev, "No PCIe Intc node found\n");
+		return PTR_ERR(pcie_intc_node);
+	}
+	pp->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
+					       &intx_domain_ops, pp);
+	if (!pp->irq_domain) {
+		dev_err(dev, "Failed to get a INTx IRQ domain\n");
+		return PTR_ERR(pp->irq_domain);
+	}
+
+	return 0;
+}
+
+static irqreturn_t rockchip_pcie_subsys_irq_handler(int irq, void *arg)
+{
+	struct rockchip_pcie_port *pp = arg;
+	u32 reg;
+	u32 sub_reg;
+
+	reg = pcie_read(pp, PCIE_CLIENT_INT_STATUS);
+	if (reg & LOC_INT) {
+		dev_dbg(pp->dev, "local interrupt recived\n");
+		sub_reg = pcie_read(pp, PCIE_CORE_INT_STATUS);
+		if (sub_reg & PRFPE)
+			dev_dbg(pp->dev, "Parity error detected while reading from the PNP Receive FIFO RAM\n");
+
+		if (sub_reg & CRFPE)
+			dev_dbg(pp->dev, "Parity error detected while reading from the Completion Receive FIFO RAM\n");
+
+		if (sub_reg & RRPE)
+			dev_dbg(pp->dev, "Parity error detected while reading from Replay Buffer RAM\n");
+
+		if (sub_reg & PRFO)
+			dev_dbg(pp->dev, "Overflow occurred in the PNP Receive FIFO\n");
+
+		if (sub_reg & CRFO)
+			dev_dbg(pp->dev, "Overflow occurred in the Completion Receive FIFO\n");
+
+		if (sub_reg & RT)
+			dev_dbg(pp->dev, "Replay timer timed out\n");
+
+		if (sub_reg & RTR)
+			dev_dbg(pp->dev, "Replay timer rolled over after 4 transmissions of the same TLP\n");
+
+		if (sub_reg & PE)
+			dev_dbg(pp->dev, "Phy error detected on receive side\n");
+
+		if (sub_reg & MTR)
+			dev_dbg(pp->dev, "Malformed TLP received from the link\n");
+
+		if (sub_reg & UCR)
+			dev_dbg(pp->dev, "Malformed TLP received from the link\n");
+
+		if (sub_reg & FCE)
+			dev_dbg(pp->dev, "An error was observed in the flow control advertisements from the other side\n");
+
+		if (sub_reg & CT)
+			dev_dbg(pp->dev, "A request timed out waiting for completion\n");
+
+		if (sub_reg & UTC)
+			dev_dbg(pp->dev, "Unmapped TC error\n");
+
+		if (sub_reg & MMVC)
+			dev_dbg(pp->dev, "MSI mask register changes\n");
+
+		pcie_write(pp, sub_reg, PCIE_CORE_INT_STATUS);
+	}
+
+	pcie_write(pp, reg, PCIE_CLIENT_INT_STATUS);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rockchip_pcie_client_irq_handler(int irq, void *arg)
+{
+	struct rockchip_pcie_port *pp = arg;
+	u32 reg;
+
+	reg = pcie_read(pp, PCIE_CLIENT_INT_STATUS);
+	if (reg & LEGACY_DONE)
+		dev_dbg(pp->dev, "legacy done interrupt recived\n");
+
+	if (reg & MSG_DONE)
+		dev_dbg(pp->dev, "message done interrupt recived\n");
+
+	if (reg & HOT_RESET)
+		dev_dbg(pp->dev, "hot reset interrupt recived\n");
+
+	if (reg & DPA_INT)
+		dev_dbg(pp->dev, "dpa interrupt recived\n");
+
+	if (reg & FATAL_ERR)
+		dev_dbg(pp->dev, "fatal error interrupt recived\n");
+
+	if (reg & DPA_INT)
+		dev_dbg(pp->dev, "no fatal error interrupt recived\n");
+
+	if (reg & CORR_ERR)
+		dev_dbg(pp->dev, "correctable error interrupt recived\n");
+
+	pcie_write(pp, reg, PCIE_CLIENT_INT_STATUS);
+
+	return IRQ_HANDLED;
+}
+
+static irqreturn_t rockchip_pcie_legacy_int_handler(int irq, void *arg)
+{
+	struct rockchip_pcie_port *pp = arg;
+	u32 reg;
+
+	reg = pcie_read(pp, PCIE_CLIENT_INT_STATUS);
+	reg = (reg & ROCKCHIP_PCIE_RPIFR1_INTR_MASK) >>
+	       ROCKCHIP_PCIE_RPIFR1_INTR_SHIFT;
+	generic_handle_irq(irq_find_mapping(pp->irq_domain, ffs(reg)));
+
+	pcie_write(pp, reg, PCIE_CLIENT_INT_STATUS);
+	return IRQ_HANDLED;
+}
+
+static int rockchip_pcie_prog_ob_atu(struct rockchip_pcie_port *pp,
+				     int region_no,
+				     int type, u8 num_pass_bits,
+				     u32 lower_addr, u32 upper_addr)
+{
+	u32 ob_addr_0 = 0;
+	u32 ob_addr_1 = 0;
+	u32 ob_desc_0 = 0;
+	u32 ob_desc_1 = 0;
+	void __iomem *aw_base;
+
+	if (!pp)
+		return -EINVAL;
+	if (region_no >= MAX_AXI_WRAPPER_REGION_NUM)
+		return -EINVAL;
+	if ((num_pass_bits + 1) < 8)
+		return -EINVAL;
+	if (num_pass_bits > 63)
+		return -EINVAL;
+	if (region_no == 0) {
+		if (AXI_REGION_0_SIZE < (2ULL << num_pass_bits))
+		return -EINVAL;
+	}
+	if (region_no != 0) {
+		if (AXI_REGION_SIZE < (2ULL << num_pass_bits))
+		return -EINVAL;
+	}
+	aw_base = pp->apb_base + PCIE_CORE_AXI_CONF_BASE;
+	aw_base += (region_no << OB_REG_SIZE_SHIFT);
+
+	ob_addr_0 = (ob_addr_0 &
+		     ~0x0000003fU) | (num_pass_bits &
+		     0x0000003fU);
+	ob_addr_0 = (ob_addr_0 &
+		     ~0xffffff00U) | (lower_addr & 0xffffff00U);
+	ob_addr_1 = upper_addr;
+	ob_desc_0 = (1 << 23 | type);
+
+	writel(ob_addr_0, aw_base);
+	writel(ob_addr_1, aw_base + 0x4);
+	writel(ob_desc_0, aw_base + 0x8);
+	writel(ob_desc_1, aw_base + 0xc);
+
+	return 0;
+}
+
+static int rockchip_pcie_prog_ib_atu(struct rockchip_pcie_port *pp,
+				     int region_no,
+				     u8 num_pass_bits,
+				     u32 lower_addr,
+				     u32 upper_addr)
+{
+	u32 ib_addr_0 = 0;
+	u32 ib_addr_1 = 0;
+	void __iomem *aw_base;
+
+	if (!pp)
+		return -EINVAL;
+	if (region_no > MAX_AXI_IB_ROOTPORT_REGION_NUM)
+		return -EINVAL;
+	if ((num_pass_bits + 1) < MIN_AXI_ADDR_BITS_PASSED)
+		return -EINVAL;
+	if (num_pass_bits > 63)
+		return -EINVAL;
+	aw_base = pp->apb_base + PCIE_CORE_AXI_INBOUND_BASE;
+	aw_base += (region_no << IB_ROOT_PORT_REG_SIZE_SHIFT);
+	ib_addr_0 = (ib_addr_0 &
+		     ~0x0000003fU) | (num_pass_bits &
+		     0x0000003fU);
+
+	ib_addr_0 = (ib_addr_0 & ~0xffffff00U) |
+		     ((lower_addr << 8) & 0xffffff00U);
+	ib_addr_1 = upper_addr;
+	writel(ib_addr_0, aw_base);
+	writel(ib_addr_1, aw_base + 0x4);
+
+	return 0;
+}
+
+static int rockchip_pcie_probe(struct platform_device *pdev)
+{
+	struct rockchip_pcie_port *port;
+	struct device *dev = &pdev->dev;
+	struct pci_bus *bus, *child;
+	struct resource_entry *win;
+	int reg_no;
+	int err = 0;
+	int irq;
+	LIST_HEAD(res);
+
+	if (!dev->of_node)
+		return -ENODEV;
+
+	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
+	if (!port)
+		return -ENOMEM;
+
+	irq = platform_get_irq_byname(pdev, "pcie-sys");
+	if (irq < 0) {
+		dev_err(dev, "missing pcie_sys IRQ resource\n");
+		return -EINVAL;
+	}
+	err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler,
+			       IRQF_SHARED, "pcie-sys", port);
+	if (err) {
+		dev_err(dev, "failed to request pcie subsystem irq\n");
+		return err;
+	}
+
+	port->irq = platform_get_irq_byname(pdev, "pcie-legacy");
+	if (port->irq < 0) {
+		dev_err(dev, "missing pcie_legacy IRQ resource\n");
+		return -EINVAL;
+	}
+	err = devm_request_irq(dev, port->irq,
+			       rockchip_pcie_legacy_int_handler,
+			       IRQF_SHARED,
+			       "pcie-legacy",
+			       port);
+	if (err) {
+		dev_err(&pdev->dev, "failed to request pcie-legacy irq\n");
+		return err;
+	}
+
+	irq = platform_get_irq_byname(pdev, "pcie-client");
+	if (irq < 0) {
+		dev_err(dev, "missing pcie-client IRQ resource\n");
+		return -EINVAL;
+	}
+	err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler,
+			       IRQF_SHARED, "pcie-client", port);
+	if (err) {
+		dev_err(dev, "failed to request pcie client irq\n");
+		return err;
+	}
+
+	port->dev = dev;
+	err = rockchip_pcie_parse_dt(port);
+	if (err) {
+		dev_err(dev, "Parsing DT failed\n");
+		return err;
+	}
+
+	err = rockchip_pcie_init_port(port);
+	if (err)
+		return err;
+
+	platform_set_drvdata(pdev, port);
+
+	rockchip_pcie_enable_interrupts(port);
+	if (!IS_ENABLED(CONFIG_PCI_MSI)) {
+		err = rockchip_pcie_init_irq_domain(port);
+		if (err < 0)
+			return err;
+	}
+
+	err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff,
+					       &res, &port->io_base);
+	if (err)
+		return err;
+	/* Get the I/O and memory ranges from DT */
+	resource_list_for_each_entry(win, &res) {
+		switch (resource_type(win->res)) {
+		case IORESOURCE_IO:
+			port->io = win->res;
+			port->io->name = "I/O";
+			port->io_size = resource_size(port->io);
+			port->io_bus_addr = port->io->start - win->offset;
+			err = pci_remap_iospace(port->io, port->io_base);
+			if (err) {
+				dev_warn(port->dev, "error %d: failed to map resource %pR\n",
+					 err, port->io);
+				continue;
+			}
+			break;
+		case IORESOURCE_MEM:
+			port->mem = win->res;
+			port->mem->name = "MEM";
+			port->mem_size = resource_size(port->mem);
+			port->mem_bus_addr = port->mem->start - win->offset;
+			break;
+		case 0:
+			port->cfg = win->res;
+			break;
+		case IORESOURCE_BUS:
+			port->busn = win->res;
+			break;
+		default:
+			continue;
+		}
+	}
+
+	pcie_write(port, 0x6040000, PCIE_RC_CONFIG_BASE + 0x8);
+	pcie_write(port, 0x0, PCIE_CORE_CTRL_MGMT_BASE + 0x300);
+
+	pcie_write(port, (RC_REGION_0_ADDR_TRANS_L + RC_REGION_0_PASS_BITS),
+		   PCIE_CORE_AXI_CONF_BASE);
+	pcie_write(port, RC_REGION_0_ADDR_TRANS_H,
+		   PCIE_CORE_AXI_CONF_BASE + 0x4);
+	pcie_write(port, 0x0080000a, PCIE_CORE_AXI_CONF_BASE + 0x8);
+	pcie_write(port, 0x00000000, PCIE_CORE_AXI_CONF_BASE + 0xc);
+
+	for (reg_no = 0; reg_no < (port->mem_size >> 20); reg_no++) {
+		err = rockchip_pcie_prog_ob_atu(port, reg_no + 1,
+						AXI_WRAPPER_MEM_WRITE,
+						20 - 1,
+						port->mem_bus_addr +
+							(reg_no << 20),
+						0);
+		if (err) {
+			dev_err(dev, "Program RC outbound atu failed\n");
+			return err;
+		}
+	}
+
+	err = rockchip_pcie_prog_ib_atu(port, 2, 32 - 1, 0x0, 0);
+	if (err) {
+		dev_err(dev, "Program RC inbound atu failed\n");
+		return err;
+	}
+
+	rockchip_pcie_msi_enable(port);
+
+	port->root_bus_nr = port->busn->start;
+	if (IS_ENABLED(CONFIG_PCI_MSI)) {
+		bus = pci_scan_root_bus_msi(port->dev, port->root_bus_nr,
+					    &rockchip_pcie_ops, port, &res,
+					    port->msi);
+	} else {
+		bus = pci_scan_root_bus(&pdev->dev, 0,
+					&rockchip_pcie_ops, port, &res);
+	}
+	if (!bus)
+		return -ENOMEM;
+
+	if (!pci_has_flag(PCI_PROBE_ONLY)) {
+		pci_bus_size_bridges(bus);
+		pci_bus_assign_resources(bus);
+		list_for_each_entry(child, &bus->children, node)
+			pcie_bus_configure_settings(child);
+	}
+
+	pci_bus_add_devices(bus);
+
+	return err;
+}
+
+static int rockchip_pcie_remove(struct platform_device *pdev)
+{
+	struct rockchip_pcie_port *port = platform_get_drvdata(pdev);
+
+	clk_disable_unprepare(port->hclk_pcie);
+	clk_disable_unprepare(port->aclk_perf_pcie);
+	clk_disable_unprepare(port->aclk_pcie);
+	clk_disable_unprepare(port->clk_pciephy_ref);
+
+	return 0;
+}
+
+static const struct of_device_id rockchip_pcie_of_match[] = {
+	{ .compatible = "rockchip,rk3399-pcie", },
+	{}
+};
+
+static struct platform_driver rockchip_pcie_driver = {
+	.driver = {
+		.name = "rockchip-pcie",
+		.of_match_table = rockchip_pcie_of_match,
+		.suppress_bind_attrs = true,
+	},
+	.probe = rockchip_pcie_probe,
+	.remove = rockchip_pcie_remove,
+};
+module_platform_driver(rockchip_pcie_driver);
+
+MODULE_AUTHOR("Rockchip Inc");
+MODULE_DESCRIPTION("Rockchip AXI PCIe driver");
+MODULE_LICENSE("GPL v2");
-- 
2.3.7




From heiko at sntech.de  Fri May 20 04:20:06 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 20 May 2016 13:20:06 +0200
Subject: [PATCH 1/2] Documentation: add binding description of Rockchip
 PCIe controller
In-Reply-To: <1463740146-7106-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740146-7106-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <3930626.4a3xBnzHhK@phil>

Hi Shawn,

Am Freitag, 20. Mai 2016, 18:29:06 schrieb Shawn Lin:
> This patch add some required and optional properties for Rockchip
> PCIe controller. Also we add a example for how to use it.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> 
> ---
> 
>  .../devicetree/bindings/pci/rockchip-pcie.txt      | 93
> ++++++++++++++++++++++ 1 file changed, 93 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/pci/rockchip-pcie.txt
> 
> diff --git a/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
> b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt new file mode
> 100644
> index 0000000..69a0804
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
> @@ -0,0 +1,93 @@
> +* Rockchip AXI PCIe Root Port Bridge DT description
> +
> +Required properties:
> +- #address-cells: Address representation for root ports, set to <3>
> +- #size-cells: Size representation for root ports, set to <2>
> +- #interrupt-cells: specifies the number of cells needed to encode an
> +		interrupt source. The value must be 1.
> +- compatible: Should contain "rockchip,rk3399-pcie"
> +- reg: Two register ranges as listed in the reg-names property
> +- reg-names: The first entry must be "axi-base" for the core registers
> +	The second entry must be "apb-base" for the client pcie registers
> +- clocks: Must contain an entry for each entry in clock-names.
> +		See ../clocks/clock-bindings.txt for details.
> +- clock-names: Must include the following entries:
> +	- "aclk_pcie"
> +	- "aclk_perf_pcie"
> +	- "hclk_pcie"
> +	- "clk_pciephy_ref"

clock names are always in the scope of the node/driver, so the names could 
easily be "aclk", "aclk-perf", "hclk", "phy".

Although from my cursory-glance at the phy-related code, it looks more like 
it shouldn't be in the pcie-driver itself, but in a an actual phy-driver 
(together with the phy reset and clock)?

> +- interrupts: Three interrupt entries must be specified.
> +- interrupt-names: Must include the following names
> +	- "pcie-sys"
> +	- "pcie-legacy"
> +	- "pcie-client"

Same as above, names could simply be "sys", "legacy", "client"


> +- resets: Must contain five entries for each entry in reset-names.
> +	   See ../reset/reset.txt for details.
> +- reset-names: Must include the following names
> +	- "phy-rst"
> +	- "core-rst"
> +	- "mgmt-rst"
> +	- "mgmt-sticky-rst"
> +	- "pipe-rst"

and again (= without the "-rst")


> +- rockchip,grf: phandle to the syscon managing the "general register
> files" 

> +- pcie-conf: offset of pcie client block for  configuration
> +- pcie-status: offset of pcie client block for status
> +- pcie-laneoff: offset of pcie client block for lane

These are GRF offsets (GRF_SOC_CON8, GRF_SOC_CON5_PCIE, GRF_SOC_STATUS1)
Those registers are generally prone to change (even their layout) for future 
socs and I'd suggest instead of declaring them in the devicetree, move them 
to the per-soc data in the rockchip_pcie_of_match struct.

But it looks as if they're pretty phy-specific, so see comment about possible 
separate phy driver above.


> +- msi-parent: Link to the hardware entity that serves as the Message
> +- pinctrl-names : The pin control state names
> +- pinctrl-0: The "default" pinctrl state

I'm not sure if pinctrl-properties need to be described when you don't need 
special handling in the form of additional pin states. The pcie part does 
not do any pin-handling of its own.


> +- interrupt-map-mask and interrupt-map: standard PCI properties
> +- interrupt-controller: identifies the node as an interrupt controller
> +
> +Optional Property:
> +- ep-gpios: contain the entry for pre-reset gpio
> +- num-lanes: number of lanes to use
> +- assigned-clocks, assigned-clock-parents and assigned-clock-rates:
> standard +		   clock bindings. See ../clock/clock-bindings.txt

Again that (assigned-clocks handling) is not actual part of the pci-
controllers actions, but other parts and also described already elsewhere.


Heiko


From adrian.hunter at intel.com  Fri May 20 04:44:34 2016
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Fri, 20 May 2016 14:44:34 +0300
Subject: [PATCH v4 5/5] mmc: sdhci-of-arasan: implement enhanced strobe
 callback
In-Reply-To: <1463733377-986-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
 <1463733377-986-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <573EF8A2.5070305@intel.com>

On 20/05/16 11:36, Shawn Lin wrote:
> Currently sdhci-arasan 5.1 can support enhanced strobe function,
> and we now limit it just for "arasan,sdhci-5.1". Add
> mmc-hs400-enhanced-strobe in DT to enable the function if we're
> sure our controller can support it.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> Reviewed-by: Doug Anderson <dianders at chromium.org>

Acked-by: Adrian Hunter <adrian.hunter at intel.com>

> ---
> 
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/mmc/host/sdhci-of-arasan.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)
> 
> diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
> index b6f4c1d..533e2bc 100644
> --- a/drivers/mmc/host/sdhci-of-arasan.c
> +++ b/drivers/mmc/host/sdhci-of-arasan.c
> @@ -25,7 +25,9 @@
>  #include "sdhci-pltfm.h"
>  
>  #define SDHCI_ARASAN_CLK_CTRL_OFFSET	0x2c
> +#define SDHCI_ARASAN_VENDOR_REGISTER	0x78
>  
> +#define VENDOR_ENHANCED_STROBE		BIT(0)
>  #define CLK_CTRL_TIMEOUT_SHIFT		16
>  #define CLK_CTRL_TIMEOUT_MASK		(0xf << CLK_CTRL_TIMEOUT_SHIFT)
>  #define CLK_CTRL_TIMEOUT_MIN_EXP	13
> @@ -79,6 +81,21 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
>  	}
>  }
>  
> +static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
> +					struct mmc_ios *ios)
> +{
> +	u32 vendor;
> +	struct sdhci_host *host = mmc_priv(mmc);
> +
> +	vendor = readl(host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
> +	if (ios->enhanced_strobe)
> +		vendor |= VENDOR_ENHANCED_STROBE;
> +	else
> +		vendor &= ~VENDOR_ENHANCED_STROBE;
> +
> +	writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
> +}
> +
>  static struct sdhci_ops sdhci_arasan_ops = {
>  	.set_clock = sdhci_arasan_set_clock,
>  	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
> @@ -245,6 +262,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
>  			dev_err(&pdev->dev, "phy_power_on err.\n");
>  			goto err_phy_power;
>  		}
> +
> +		host->mmc_host_ops.hs400_enhanced_strobe =
> +					sdhci_arasan_hs400_enhanced_strobe;
>  	}
>  
>  	ret = sdhci_add_host(host);
> 



From shawn.lin at rock-chips.com  Fri May 20 04:55:39 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 19:55:39 +0800
Subject: [PATCH v4 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <573EDFE0.6000600@intel.com>
References: <1463733285-770-1-git-send-email-shawn.lin@rock-chips.com>
 <1463733360-902-1-git-send-email-shawn.lin@rock-chips.com>
 <573EDFE0.6000600@intel.com>
Message-ID: <5295826d-462b-d624-508a-80829b076e1e@rock-chips.com>

On 2016/5/20 17:58, Adrian Hunter wrote:
> On 20/05/16 11:36, Shawn Lin wrote:
>> Controllers use data strobe line to latch data from devices
>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>> introduces enhanced strobe mode for latching cmd response from
>> emmc devices to host controllers. This new feature is optional,
>> so it depends both on device's cap and host's cap to decide
>> whether to use it or not.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> ---
>>
>> Changes in v4: None
>> Changes in v3: None
>> Changes in v2: None
>>
>>  drivers/mmc/core/bus.c   |  3 +-
>>  drivers/mmc/core/core.c  |  8 +++++
>>  drivers/mmc/core/mmc.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
>>  include/linux/mmc/card.h |  1 +
>>  include/linux/mmc/host.h | 11 +++++++
>>  include/linux/mmc/mmc.h  |  3 ++
>>  6 files changed, 107 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> index 4bc48f1..c64266f 100644
>> --- a/drivers/mmc/core/bus.c
>> +++ b/drivers/mmc/core/bus.c
>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>  			mmc_card_ddr52(card) ? "DDR " : "",
>>  			type);
>>  	} else {
>> -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>> +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>  			mmc_hostname(card->host),
>>  			mmc_card_uhs(card) ? "ultra high speed " :
>>  			(mmc_card_hs(card) ? "high speed " : ""),
>>  			mmc_card_hs400(card) ? "HS400 " :
>>  			(mmc_card_hs200(card) ? "HS200 " : ""),
>> +			mmc_card_hs400es(card) ? "Enhanced strobe " : "",
>>  			mmc_card_ddr52(card) ? "DDR " : "",
>>  			uhs_bus_speed_mode, type, card->rca);
>>  	}
>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> index 99275e4..a559501 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -1127,6 +1127,14 @@ void mmc_set_initial_state(struct mmc_host *host)
>>  	host->ios.bus_width = MMC_BUS_WIDTH_1;
>>  	host->ios.timing = MMC_TIMING_LEGACY;
>>  	host->ios.drv_type = 0;
>> +	host->ios.enhanced_strobe = false;
>> +
>> +	/*
>> +	 * Make sure we are in non-enhanced strobe mode before we
>> +	 * actually enable it in ext_csd.
>> +	 */
>> +	if (host->ops->hs400_enhanced_strobe)
>> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
>
> We probably shouldn't call hs400_enhanced_strobe() if the host controller
> driver hasn't set MMC_CAP2_HS400_ES.

Ahh...Make sense, will fix it.

Thanks.

>
>>
>>  	mmc_set_ios(host);
>>  }
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index f99c47e..9dc91ba 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>>  		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>>  	}
>>
>> +	if ((caps2 & MMC_CAP2_HS400_ES) &&
>> +	    card->ext_csd.strobe_support &&
>> +	    (avail_type & EXT_CSD_CARD_TYPE_HS400))
>> +		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
>> +
>>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>>  	card->mmc_avail_type = avail_type;
>> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>  			mmc_card_set_blockaddr(card);
>>  	}
>>
>> +	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>>  	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>  	mmc_select_card_type(card);
>>
>> @@ -1216,6 +1222,78 @@ out_err:
>>  	return err;
>>  }
>>
>> +static int mmc_select_hs400es(struct mmc_card *card)
>> +{
>> +	struct mmc_host *host = card->host;
>> +	int err = 0;
>> +	u8 val;
>> +
>> +	if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
>> +		err = -ENOTSUPP;
>> +		goto out_err;
>> +	}
>> +
>> +	err = mmc_select_bus_width(card);
>> +	if (IS_ERR_VALUE(err))
>> +		goto out_err;
>> +
>> +	/* Switch card to HS mode */
>> +	err = mmc_select_hs(card);
>> +	if (err) {
>> +		pr_err("%s: switch to high-speed failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	err = mmc_switch_status(card);
>> +	if (err)
>> +		goto out_err;
>> +
>> +	/* Switch card to DDR with strobe bit */
>> +	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
>> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +			 EXT_CSD_BUS_WIDTH,
>> +			 val,
>> +			 card->ext_csd.generic_cmd6_time);
>> +	if (err) {
>> +		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	/* Switch card to HS400 */
>> +	val = EXT_CSD_TIMING_HS400 |
>> +	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
>> +	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +			   EXT_CSD_HS_TIMING, val,
>> +			   card->ext_csd.generic_cmd6_time,
>> +			   true, false, true);
>> +	if (err) {
>> +		pr_err("%s: switch to hs400es failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	/* Set host controller to HS400 timing and frequency */
>> +	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>> +
>> +	/* Controller enable enhanced strobe function */
>> +	host->ios.enhanced_strobe = true;
>> +	if (host->ops->hs400_enhanced_strobe)
>> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
>> +
>> +	err = mmc_switch_status(card);
>> +	if (err)
>> +		goto out_err;
>> +
>> +	return 0;
>> +
>> +out_err:
>> +	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
>> +	       __func__, err);
>> +	return err;
>> +}
>> +
>>  static void mmc_select_driver_type(struct mmc_card *card)
>>  {
>>  	int card_drv_type, drive_strength, drv_type;
>> @@ -1297,7 +1375,7 @@ err:
>>  }
>>
>>  /*
>> - * Activate High Speed or HS200 mode if supported.
>> + * Activate High Speed, HS200 or HS400ES mode if supported.
>>   */
>>  static int mmc_select_timing(struct mmc_card *card)
>>  {
>> @@ -1306,7 +1384,9 @@ static int mmc_select_timing(struct mmc_card *card)
>>  	if (!mmc_can_ext_csd(card))
>>  		goto bus_speed;
>>
>> -	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
>> +		err = mmc_select_hs400es(card);
>> +	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>  		err = mmc_select_hs200(card);
>>  	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>  		err = mmc_select_hs(card);
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index eb0151b..22defc2 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>>  	u8			raw_partition_support;	/* 160 */
>>  	u8			raw_rpmb_size_mult;	/* 168 */
>>  	u8			raw_erased_mem_count;	/* 181 */
>> +	u8			strobe_support;		/* 184 */
>>  	u8			raw_ext_csd_structure;	/* 194 */
>>  	u8			raw_card_type;		/* 196 */
>>  	u8			raw_driver_strength;	/* 197 */
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index 2a06fb0..0eabb72 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -19,6 +19,7 @@
>>
>>  #include <linux/mmc/core.h>
>>  #include <linux/mmc/card.h>
>> +#include <linux/mmc/mmc.h>
>>  #include <linux/mmc/pm.h>
>>
>>  struct mmc_ios {
>> @@ -77,6 +78,8 @@ struct mmc_ios {
>>  #define MMC_SET_DRIVER_TYPE_A	1
>>  #define MMC_SET_DRIVER_TYPE_C	2
>>  #define MMC_SET_DRIVER_TYPE_D	3
>> +
>> +	bool enhanced_strobe;			/* hs400es selection */
>>  };
>>
>>  struct mmc_host_ops {
>> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>>
>>  	/* Prepare HS400 target operating frequency depending host driver */
>>  	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>> +	/* Prepare enhanced strobe depending host driver */
>> +	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
>> +					 struct mmc_ios *ios);
>>  	int	(*select_drive_strength)(struct mmc_card *card,
>>  					 unsigned int max_dtr, int host_drv,
>>  					 int card_drv, int *drv_type);
>> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>>  	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>>  }
>>
>> +static inline bool mmc_card_hs400es(struct mmc_card *card)
>> +{
>> +	return card->host->ios.enhanced_strobe;
>> +}
>> +
>>  void mmc_retune_timer_stop(struct mmc_host *host);
>>
>>  static inline void mmc_retune_needed(struct mmc_host *host)
>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> index 15f2c4a..c376209 100644
>> --- a/include/linux/mmc/mmc.h
>> +++ b/include/linux/mmc/mmc.h
>> @@ -297,6 +297,7 @@ struct _mmc_csd {
>>  #define EXT_CSD_PART_CONFIG		179	/* R/W */
>>  #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
>>  #define EXT_CSD_BUS_WIDTH		183	/* R/W */
>> +#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
>>  #define EXT_CSD_HS_TIMING		185	/* R/W */
>>  #define EXT_CSD_POWER_CLASS		187	/* R/W */
>>  #define EXT_CSD_REV			192	/* RO */
>> @@ -380,12 +381,14 @@ struct _mmc_csd {
>>  #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
>>  #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
>>  					 EXT_CSD_CARD_TYPE_HS400_1_2V)
>> +#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
>>
>>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
>>  #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
>>  #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
>>
>>  #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
>>  #define EXT_CSD_TIMING_HS	1	/* High speed */
>>
>
>
>
>


-- 
Best Regards
Shawn Lin



From shawn.lin at kernel-upstream.org  Fri May 20 05:35:53 2016
From: shawn.lin at kernel-upstream.org (Shawn Lin)
Date: Fri, 20 May 2016 20:35:53 +0800
Subject: [PATCH v2 3/3] ARM: dts: rockchip: fixes the spi compatible for
 rk3036
In-Reply-To: <1463702182-5188-3-git-send-email-wxt@rock-chips.com>
References: <1463702182-5188-1-git-send-email-wxt@rock-chips.com>
 <1463702182-5188-3-git-send-email-wxt@rock-chips.com>
Message-ID: <8f662b3b-e359-efdf-72e5-c4f862dd1cf6@kernel-upstream.org>

? 2016/5/20 7:56, Caesar Wang ??:
> That's seem the incorrect string to match the spi driver.
>

Will it break the backward compatibility for some dtb if not
falling back to "rockchip,rockchip-spi" ?

> Fixes commit f629fcfab2cd
> ("ARM: dts: rockchip: support the spi for rk3036")
>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Cc: linux-rockchip at lists.infradead.org
>
> ---
>
> Changes in v2: None
>
>  arch/arm/boot/dts/rk3036.dtsi | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm/boot/dts/rk3036.dtsi b/arch/arm/boot/dts/rk3036.dtsi
> index d0f4bb7..a30700a 100644
> --- a/arch/arm/boot/dts/rk3036.dtsi
> +++ b/arch/arm/boot/dts/rk3036.dtsi
> @@ -431,7 +431,7 @@
>  	};
>
>  	spi: spi at 20074000 {
> -		compatible = "rockchip,rockchip-spi";
> +		compatible = "rockchip,rk3036-spi";
>  		reg = <0x20074000 0x1000>;
>  		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
>  		clocks =<&cru PCLK_SPI>, <&cru SCLK_SPI>;
>



From shawn.lin at rock-chips.com  Fri May 20 05:55:56 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 20:55:56 +0800
Subject: [PATCH] arm64: dts: rockchip: fixes the gic400 2nd region size
 for rk3368
In-Reply-To: <1463582510-29156-1-git-send-email-wxt@rock-chips.com>
References: <1463582510-29156-1-git-send-email-wxt@rock-chips.com>
Message-ID: <61133267-f903-b580-7737-b77610392cde@rock-chips.com>

? 2016/5/18 22:41, Caesar Wang ??:
> The 2nd additional region is the GIC virtual cpu interface register
> base and size.
>
> As the gic400 of rk3368 says, the cpu interface register map as below
>
> :
>
> -0x0000 GICC_CTRL
> .
> .
> .
> -0x00fc GICC_IIDR
> -0x1000 GICC_IDR
>
> Obviously, the region size should be greater than 0x1000.
> So we should make sure to include the GICC_IDR since the kernel will access
> it in some cases.
>

yes, address range for GICC_* should be from 0x2000 to 0x3fff according
to gic400 memory map Table 3-1.

Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>

> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-rockchip at lists.infradead.org
>
> ---
>
>  arch/arm64/boot/dts/rockchip/rk3368.dtsi | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
> index 8b4a7c9..080203e 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
> @@ -670,7 +670,7 @@
>  		#address-cells = <0>;
>
>  		reg = <0x0 0xffb71000 0x0 0x1000>,
> -		      <0x0 0xffb72000 0x0 0x1000>,
> +		      <0x0 0xffb72000 0x0 0x2000>,
>  		      <0x0 0xffb74000 0x0 0x2000>,
>  		      <0x0 0xffb76000 0x0 0x2000>;
>  		interrupts = <GIC_PPI 9
>


-- 
Best Regards
Shawn Lin



From wxt at rock-chips.com  Fri May 20 05:57:03 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 20 May 2016 20:57:03 +0800
Subject: [PATCH v2 3/3] ARM: dts: rockchip: fixes the spi compatible for
 rk3036
In-Reply-To: <8f662b3b-e359-efdf-72e5-c4f862dd1cf6@kernel-upstream.org>
References: <1463702182-5188-1-git-send-email-wxt@rock-chips.com>
 <1463702182-5188-3-git-send-email-wxt@rock-chips.com>
 <8f662b3b-e359-efdf-72e5-c4f862dd1cf6@kernel-upstream.org>
Message-ID: <573F099F.1020603@rock-chips.com>


? 2016?05?20? 20:35, Shawn Lin ??:
> ? 2016/5/20 7:56, Caesar Wang ??:
>> That's seem the incorrect string to match the spi driver.
>>
>
> Will it break the backward compatibility for some dtb if not
> falling back to "rockchip,rockchip-spi" ?

The rk3036 shouldn't work if you read the driver/spi/spi-rockchip.c.
since the "rockchip,rockchip-spi" is *not* exist in linux kernel.

..
  static const struct of_device_id rockchip_spi_dt_match[] = {
     { .compatible = "rockchip,rk3066-spi", },
     { .compatible = "rockchip,rk3188-spi", },
     { .compatible = "rockchip,rk3288-spi", },
     { .compatible = "rockchip,rk3399-spi", },
     { },
}
..


-Caesar

>
>> Fixes commit f629fcfab2cd
>> ("ARM: dts: rockchip: support the spi for rk3036")
>>
>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>> Cc: Heiko Stuebner <heiko at sntech.de>
>> Cc: linux-rockchip at lists.infradead.org
>>
>> ---
>>
>> Changes in v2: None
>>
>>  arch/arm/boot/dts/rk3036.dtsi | 2 +-
>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/boot/dts/rk3036.dtsi 
>> b/arch/arm/boot/dts/rk3036.dtsi
>> index d0f4bb7..a30700a 100644
>> --- a/arch/arm/boot/dts/rk3036.dtsi
>> +++ b/arch/arm/boot/dts/rk3036.dtsi
>> @@ -431,7 +431,7 @@
>>      };
>>
>>      spi: spi at 20074000 {
>> -        compatible = "rockchip,rockchip-spi";
>> +        compatible = "rockchip,rk3036-spi";
>>          reg = <0x20074000 0x1000>;
>>          interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
>>          clocks =<&cru PCLK_SPI>, <&cru SCLK_SPI>;
>>
>
>
>
>

-- 
caesar wang | software engineer | wxt at rock-chip.com




From heiko at sntech.de  Fri May 20 05:58:27 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 20 May 2016 14:58:27 +0200
Subject: [PATCH v2 3/3] ARM: dts: rockchip: fixes the spi compatible for
 rk3036
In-Reply-To: <8f662b3b-e359-efdf-72e5-c4f862dd1cf6@kernel-upstream.org>
References: <1463702182-5188-1-git-send-email-wxt@rock-chips.com>
 <1463702182-5188-3-git-send-email-wxt@rock-chips.com>
 <8f662b3b-e359-efdf-72e5-c4f862dd1cf6@kernel-upstream.org>
Message-ID: <28155403.nCsUkeXQB1@phil>

Am Freitag, 20. Mai 2016, 20:35:53 schrieb Shawn Lin:
> ? 2016/5/20 7:56, Caesar Wang ??:
> > That's seem the incorrect string to match the spi driver.
> 
> Will it break the backward compatibility for some dtb if not
> falling back to "rockchip,rockchip-spi" ?

in what dtb did you see "rockchip,rockchip-spi"?
I.e. it isn't part of any current _mainline_ devicetree files.


Heiko

> 
> > Fixes commit f629fcfab2cd
> > ("ARM: dts: rockchip: support the spi for rk3036")
> > 
> > Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> > Cc: Heiko Stuebner <heiko at sntech.de>
> > Cc: linux-rockchip at lists.infradead.org
> > 
> > ---
> > 
> > Changes in v2: None
> > 
> >  arch/arm/boot/dts/rk3036.dtsi | 2 +-
> >  1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/arch/arm/boot/dts/rk3036.dtsi
> > b/arch/arm/boot/dts/rk3036.dtsi index d0f4bb7..a30700a 100644
> > --- a/arch/arm/boot/dts/rk3036.dtsi
> > +++ b/arch/arm/boot/dts/rk3036.dtsi
> > @@ -431,7 +431,7 @@
> > 
> >  	};
> >  	
> >  	spi: spi at 20074000 {
> > 
> > -		compatible = "rockchip,rockchip-spi";
> > +		compatible = "rockchip,rk3036-spi";
> > 
> >  		reg = <0x20074000 0x1000>;
> >  		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
> >  		clocks =<&cru PCLK_SPI>, <&cru SCLK_SPI>;



From shawn.lin at rock-chips.com  Fri May 20 06:04:57 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 21:04:57 +0800
Subject: [PATCH v2 3/3] ARM: dts: rockchip: fixes the spi compatible for
 rk3036
In-Reply-To: <573F099F.1020603@rock-chips.com>
References: <1463702182-5188-1-git-send-email-wxt@rock-chips.com>
 <1463702182-5188-3-git-send-email-wxt@rock-chips.com>
 <8f662b3b-e359-efdf-72e5-c4f862dd1cf6@kernel-upstream.org>
 <573F099F.1020603@rock-chips.com>
Message-ID: <e538d784-2860-04e9-1e8c-45c8769561f9@rock-chips.com>

? 2016/5/20 20:57, Caesar Wang ??:
>
> ? 2016?05?20? 20:35, Shawn Lin ??:
>> ? 2016/5/20 7:56, Caesar Wang ??:
>>> That's seem the incorrect string to match the spi driver.
>>>
>>
>> Will it break the backward compatibility for some dtb if not
>> falling back to "rockchip,rockchip-spi" ?
>
> The rk3036 shouldn't work if you read the driver/spi/spi-rockchip.c.
> since the "rockchip,rockchip-spi" is *not* exist in linux kernel.
>

okay, so that means we take "rockchip,rockchip-spi" from local branch
by mistake?

> ..
>  static const struct of_device_id rockchip_spi_dt_match[] = {
>     { .compatible = "rockchip,rk3066-spi", },
>     { .compatible = "rockchip,rk3188-spi", },
>     { .compatible = "rockchip,rk3288-spi", },
>     { .compatible = "rockchip,rk3399-spi", },
>     { },
> }
> ..
>
>
> -Caesar
>
>>
>>> Fixes commit f629fcfab2cd
>>> ("ARM: dts: rockchip: support the spi for rk3036")
>>>
>>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>>> Cc: Heiko Stuebner <heiko at sntech.de>
>>> Cc: linux-rockchip at lists.infradead.org
>>>
>>> ---
>>>
>>> Changes in v2: None
>>>
>>>  arch/arm/boot/dts/rk3036.dtsi | 2 +-
>>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm/boot/dts/rk3036.dtsi
>>> b/arch/arm/boot/dts/rk3036.dtsi
>>> index d0f4bb7..a30700a 100644
>>> --- a/arch/arm/boot/dts/rk3036.dtsi
>>> +++ b/arch/arm/boot/dts/rk3036.dtsi
>>> @@ -431,7 +431,7 @@
>>>      };
>>>
>>>      spi: spi at 20074000 {
>>> -        compatible = "rockchip,rockchip-spi";
>>> +        compatible = "rockchip,rk3036-spi";
>>>          reg = <0x20074000 0x1000>;
>>>          interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
>>>          clocks =<&cru PCLK_SPI>, <&cru SCLK_SPI>;
>>>
>>
>>
>>
>>
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Fri May 20 06:09:55 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 20 May 2016 21:09:55 +0800
Subject: [PATCH v2 3/3] ARM: dts: rockchip: fixes the spi compatible for
 rk3036
In-Reply-To: <28155403.nCsUkeXQB1@phil>
References: <1463702182-5188-1-git-send-email-wxt@rock-chips.com>
 <1463702182-5188-3-git-send-email-wxt@rock-chips.com>
 <8f662b3b-e359-efdf-72e5-c4f862dd1cf6@kernel-upstream.org>
 <28155403.nCsUkeXQB1@phil>
Message-ID: <3c1e174e-035b-78ae-b045-fe89990826da@rock-chips.com>

On 2016/5/20 20:58, Heiko Stuebner wrote:
> Am Freitag, 20. Mai 2016, 20:35:53 schrieb Shawn Lin:
>> ? 2016/5/20 7:56, Caesar Wang ??:
>>> That's seem the incorrect string to match the spi driver.
>>
>> Will it break the backward compatibility for some dtb if not
>> falling back to "rockchip,rockchip-spi" ?
>
> in what dtb did you see "rockchip,rockchip-spi"?

I'm not 100% sure, but I remember we toke this name on local
branch for rk3036 when we were developing this Soc.

> I.e. it isn't part of any current _mainline_ devicetree files.
>

Caesar, Could you check our develop-3.10 branch to see if it does
exist?

Anyway, "rockchip,rockchip-spi" isn't a part of mainline dt property.


>
> Heiko
>
>>
>>> Fixes commit f629fcfab2cd
>>> ("ARM: dts: rockchip: support the spi for rk3036")
>>>
>>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>>> Cc: Heiko Stuebner <heiko at sntech.de>
>>> Cc: linux-rockchip at lists.infradead.org
>>>
>>> ---
>>>
>>> Changes in v2: None
>>>
>>>  arch/arm/boot/dts/rk3036.dtsi | 2 +-
>>>  1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm/boot/dts/rk3036.dtsi
>>> b/arch/arm/boot/dts/rk3036.dtsi index d0f4bb7..a30700a 100644
>>> --- a/arch/arm/boot/dts/rk3036.dtsi
>>> +++ b/arch/arm/boot/dts/rk3036.dtsi
>>> @@ -431,7 +431,7 @@
>>>
>>>  	};
>>>  	
>>>  	spi: spi at 20074000 {
>>>
>>> -		compatible = "rockchip,rockchip-spi";
>>> +		compatible = "rockchip,rk3036-spi";
>>>
>>>  		reg = <0x20074000 0x1000>;
>>>  		interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
>>>  		clocks =<&cru PCLK_SPI>, <&cru SCLK_SPI>;
>
>


-- 
Best Regards
Shawn Lin



From heiko at sntech.de  Fri May 20 14:13:14 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 20 May 2016 23:13:14 +0200
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <3647622.McCjKUuZmz@phil>

Hi Shawn,

I haven't had any contact with PCI yet, so my comments below will likely 
address more generic findings only.

As you might've guessed from the binding comments, to me it looks like the 
phy handling should be in a separate phy driver and looking below all phy 
accesses seem very separate from the actual pci controller interactions - 
they are even in port_init only as well.

While I already added some comments about that below, the driver seems full 
of raw register bit handling (including wild shifts). Please abstract that 
using contants, so that stuff stays readable for the future.


Am Freitag, 20. Mai 2016, 18:29:16 schrieb Shawn Lin:
> RK3399 has a PCIe controller which can be used as Root Complex.
> This driver supports a PCIe controller as Root Complex mode.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---

[...]

> diff --git a/drivers/pci/host/pcie-rockchip.c
> b/drivers/pci/host/pcie-rockchip.c new file mode 100644
> index 0000000..4063fd3
> --- /dev/null
> +++ b/drivers/pci/host/pcie-rockchip.c
> @@ -0,0 +1,1181 @@
> +/*
> + * Rockchip AXI PCIe host controller driver
> + *
> + * Copyright (c) 2016 Rockchip, Inc.
> + *
> + * Author: Shawn Lin <shawn.lin at rock-chips.com>
> + *         Wenrui Li <wenrui.li at rock-chips.com>
> + * Bits taken from Synopsys Designware Host controller driver and
> + * ARM PCI Host generic driver.
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/msi.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_pci.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_irq.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +#include <linux/regmap.h>
> +
> +#define REF_CLK_100MHZ			(100 * 1000 * 1000)

seems unused

> +#define PCIE_CLIENT_BASE		0x0
> +#define PCIE_RC_CONFIG_BASE		0xa00000
> +#define PCIE_CORE_CTRL_MGMT_BASE	0x900000
> +#define PCIE_CORE_AXI_CONF_BASE		0xc00000
> +#define PCIE_CORE_AXI_INBOUND_BASE	0xc00800
> +
> +#define PCIE_CLIENT_BASIC_STATUS0	0x44
> +#define PCIE_CLIENT_BASIC_STATUS1	0x48
> +#define PCIE_CLIENT_INT_MASK		0x4c
> +#define PCIE_CLIENT_INT_STATUS		0x50
> +#define PCIE_CORE_INT_MASK		0x900210
> +#define PCIE_CORE_INT_STATUS		0x90020c
> +
> +/** Size of one AXI Region (not Region 0) */
> +#define	AXI_REGION_SIZE			(0x1 << 20)

for those generic (1 << x) things please use BIT(x) instead
Also constants intertwined with constants is hard to read,
so ideally add a blank line above each comment and comment style for single 
line comments only has one * in the beginning
	/* foo */

> +/** Overall size of AXI area */
> +#define	AXI_OVERALL_SIZE		(64 * (0x1 << 20))
> +/** Size of Region 0, equal to sum of sizes of other regions */
> +#define	AXI_REGION_0_SIZE		(32 * (0x1 << 20))
> +#define OB_REG_SIZE_SHIFT		5
> +#define IB_ROOT_PORT_REG_SIZE_SHIFT	3
> +
> +#define AXI_WRAPPER_IO_WRITE		0x6
> +#define AXI_WRAPPER_MEM_WRITE		0x2
> +#define MAX_AXI_IB_ROOTPORT_REGION_NUM	3
> +#define	MIN_AXI_ADDR_BITS_PASSED	8

strange spacing after #define

[...]

> +/**
> + * rockchip_pcie_init_port - Initialize hardware
> + * @port: PCIe port information
> + */
> +static int rockchip_pcie_init_port(struct rockchip_pcie_port *port)
> +{
> +	int err;
> +	u32 status;
> +	unsigned long timeout = jiffies + msecs_to_jiffies(1000);

this timeout only seems to be initialized once here but used for multiple 
loops below resulting in all waitloops combined together being allowed to 
take 1 second ... is this intended?

> +	gpiod_set_value(port->ep_gpio, 0);
> +
> +	/* Make sure PCIe relate block is in reset state */
> +	err = reset_control_assert(port->phy_rst);
> +	if (err) {
> +		dev_err(port->dev, "assert phy_rst err %d\n", err);
> +		return err;
> +	}

should move to phy driver probe or so

> +	err = reset_control_assert(port->core_rst);
> +	if (err) {
> +		dev_err(port->dev, "assert core_rst err %d\n", err);
> +		return err;
> +	}

blank line

> +	err = reset_control_assert(port->mgmt_rst);
> +	if (err) {
> +		dev_err(port->dev, "assert mgmt_rst err %d\n", err);
> +		return err;
> +	}

blank line

> +	err = reset_control_assert(port->mgmt_sticky_rst);
> +	if (err) {
> +		dev_err(port->dev, "assert mgmt_sticky_rst err %d\n", err);
> +		return err;
> +	}

blank line

> +	err = reset_control_assert(port->pipe_rst);
> +	if (err) {
> +		dev_err(port->dev, "assert pipe_rst err %d\n", err);
> +		return err;
> +	}
> +
> +	pcie_write(port, (0xf << 20) | (0x1 << 16) | PCIE_CLIENT_GEN_SEL_2 |
> +			  (0x1 << 19) | (0x1 << 3) |
> +			  PCIE_CLIENT_MODE_RC |
> +			  PCIE_CLIENT_CONF_LANE_NUM(port->lanes) |
> +			  PCIE_CLIENT_CONF_ENABLE, PCIE_CLIENT_BASE);
> +

------ phy_enable begin ------

As mentioned above, the whole phy handling seems pretty separate, so should 
be easily being able to live in a real phy driver?

This of course also needs to handle the phy clock in it.

> +	err = reset_control_deassert(port->phy_rst);
> +	if (err) {
> +		dev_err(port->dev, "deassert phy_rst err %d\n", err);
> +		return err;
> +	}
> +	regmap_write(port->grf, port->pcie_conf,
> +		     (0x3f << 17) | (0x10 << 1));

the bits above should use some sort of constant / description. Also see 
HIWORD_UPDATE in other drivers for the write-enable mask

also add blank line here

> +	err = -EINVAL;
> +	while (time_before(jiffies, timeout)) {
> +		regmap_read(port->grf, port->pcie_status, &status);
> +		if ((status & (1 << 9))) {

use a constant for the (1 << 9) [aka BIT(9)] please

> +			dev_info(port->dev, "pll locked!\n");

dev_dbg instead?

> +			err = 0;
> +			break;
> +		}
> +	}
> +	if (err) {
> +		dev_err(port->dev, "pll lock timeout!\n");
> +		return err;
> +	}
> +	pcie_pb_wr_cfg(port, 0x10, 0x8);
> +	pcie_pb_wr_cfg(port, 0x12, 0x8);
> +
> +	err = -ETIMEDOUT;
> +	while (time_before(jiffies, timeout)) {
> +		regmap_read(port->grf, port->pcie_status, &status);
> +		if (!(status & (1 << 10))) {

constant again

> +			dev_info(port->dev, "pll output enable done!\n");

dev_dbg or leave it out

> +			err = 0;
> +			break;
> +		}
> +	}
> +
> +	if (err) {
> +		dev_err(port->dev, "pll output enable timeout!\n");
> +		return err;
> +	}
> +
> +	regmap_write(port->grf, port->pcie_conf,
> +		     (0x3f << 17) | (0x10 << 1));
> +	err = -EINVAL;
> +	while (time_before(jiffies, timeout)) {
> +		regmap_read(port->grf, port->pcie_status, &status);
> +		if ((status & (1 << 9))) {
> +			dev_info(port->dev, "pll relocked!\n");
> +			err = 0;
> +			break;
> +		}
> +	}
> +	if (err) {
> +		dev_err(port->dev, "pll relock timeout!\n");
> +		return err;
> +	}

------ phy_enable end ------


> +	err = reset_control_deassert(port->core_rst);
> +	if (err) {
> +		dev_err(port->dev, "deassert core_rst err %d\n", err);
> +		return err;
> +	}
> +	err = reset_control_deassert(port->mgmt_rst);
> +	if (err) {
> +		dev_err(port->dev, "deassert mgmt_rst err %d\n", err);
> +		return err;
> +	}
> +	err = reset_control_deassert(port->mgmt_sticky_rst);
> +	if (err) {
> +		dev_err(port->dev, "deassert mgmt_sticky_rst err %d\n", err);
> +		return err;
> +	}
> +	err = reset_control_deassert(port->pipe_rst);
> +	if (err) {
> +		dev_err(port->dev, "deassert pipe_rst err %d\n", err);
> +		return err;
> +	}
> +
> +	pcie_write(port, 1 << 17 | 1 << 1, PCIE_CLIENT_BASE);
> +
> +	gpiod_set_value(port->ep_gpio, 1);
> +	err = -ETIMEDOUT;
> +	while (time_before(jiffies, timeout)) {
> +		status = pcie_read(port, PCIE_CLIENT_BASIC_STATUS1);
> +		if (((status >> 20) & 0x3) == 0x3) {
> +			dev_info(port->dev, "pcie link training gen1 pass!\n");
> +			err = 0;
> +			break;
> +		}
> +	}
> +	if (err) {
> +		dev_err(port->dev, "pcie link training gen1 timeout!\n");
> +		return err;
> +	}
> +
> +	status = pcie_read(port, 0x9000d0);
> +	status |= 0x20;
> +	pcie_write(port, status, 0x9000d0);

just to mention it again, bit handling as descriptive constant please and 
also please give that register a name :-)

[...]

> +static int rockchip_pcie_parse_dt(struct rockchip_pcie_port *port)
> +{

[...]

> +	port->lanes = 1;
> +	err = of_property_read_u32(node, "num-lanes", &port->lanes);
> +	if (!err && ((port->lanes == 0) ||
> +		     (port->lanes == 3) ||
> +		     (port->lanes > 4))) {
> +		dev_info(dev, "invalid num-lanes, default use one lane\n");

dev_warn might be more appropriate

> +		port->lanes = 1;
> +	}

[...]

> +static void rockchip_pcie_msi_enable(struct rockchip_pcie_port *pp)
> +{
> +	struct device_node *msi_node;
> +
> +	msi_node = of_parse_phandle(pp->dev->of_node,
> +				    "msi-parent", 0);

I would assume this should live in the general parse_dt function?
Also is that MSI enablement really allow to fail silently without any affect 
on the PCI functionality?

> +	if (!msi_node)
> +		return;
> +
> +	pp->msi = of_pci_find_msi_chip_by_node(msi_node);
> +	of_node_put(msi_node);
> +
> +	if (pp->msi)
> +		pp->msi->dev = pp->dev;
> +}

[...]

> +static int rockchip_pcie_probe(struct platform_device *pdev)
> +{
> +	struct rockchip_pcie_port *port;
> +	struct device *dev = &pdev->dev;
> +	struct pci_bus *bus, *child;
> +	struct resource_entry *win;
> +	int reg_no;
> +	int err = 0;
> +	int irq;
> +	LIST_HEAD(res);
> +
> +	if (!dev->of_node)
> +		return -ENODEV;
> +
> +	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> +	if (!port)
> +		return -ENOMEM;
> +
> +	irq = platform_get_irq_byname(pdev, "pcie-sys");
> +	if (irq < 0) {
> +		dev_err(dev, "missing pcie_sys IRQ resource\n");
> +		return -EINVAL;
> +	}

blank line

> +	err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler,
> +			       IRQF_SHARED, "pcie-sys", port);
> +	if (err) {
> +		dev_err(dev, "failed to request pcie subsystem irq\n");
> +		return err;
> +	}
> +
> +	port->irq = platform_get_irq_byname(pdev, "pcie-legacy");
> +	if (port->irq < 0) {
> +		dev_err(dev, "missing pcie_legacy IRQ resource\n");
> +		return -EINVAL;
> +	}

blank line

> +	err = devm_request_irq(dev, port->irq,
> +			       rockchip_pcie_legacy_int_handler,
> +			       IRQF_SHARED,
> +			       "pcie-legacy",
> +			       port);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to request pcie-legacy irq\n");
> +		return err;
> +	}
> +
> +	irq = platform_get_irq_byname(pdev, "pcie-client");
> +	if (irq < 0) {
> +		dev_err(dev, "missing pcie-client IRQ resource\n");
> +		return -EINVAL;
> +	}

blank line

> +	err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler,
> +			       IRQF_SHARED, "pcie-client", port);
> +	if (err) {
> +		dev_err(dev, "failed to request pcie client irq\n");
> +		return err;
> +	}
> +
> +	port->dev = dev;
> +	err = rockchip_pcie_parse_dt(port);
> +	if (err) {
> +		dev_err(dev, "Parsing DT failed\n");
> +		return err;
> +	}

rockchip_pcie_parse_dt already emits error messages that are a lot more 
specific to the actual problem, so you don't need another error message here 
and can just return the error code.


> +	err = rockchip_pcie_init_port(port);
> +	if (err)
> +		return err;
> +
> +	platform_set_drvdata(pdev, port);
> +
> +	rockchip_pcie_enable_interrupts(port);
> +	if (!IS_ENABLED(CONFIG_PCI_MSI)) {
> +		err = rockchip_pcie_init_irq_domain(port);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff,
> +					       &res, &port->io_base);
> +	if (err)
> +		return err;

add blank line


Heiko


From heiko at sntech.de  Fri May 20 14:19:52 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 20 May 2016 23:19:52 +0200
Subject: [PATCH] arm64: dts: rockchip: fixes the gic400 2nd region size
 for rk3368
In-Reply-To: <1463582510-29156-1-git-send-email-wxt@rock-chips.com>
References: <1463582510-29156-1-git-send-email-wxt@rock-chips.com>
Message-ID: <2773450.t8WTDyMWXy@phil>

Hi Caesar,

Am Mittwoch, 18. Mai 2016, 22:41:50 schrieb Caesar Wang:
> The 2nd additional region is the GIC virtual cpu interface register
> base and size.
> 
> As the gic400 of rk3368 says, the cpu interface register map as below
> 
> 
> 
> -0x0000 GICC_CTRL
> .
> .
> .
> -0x00fc GICC_IIDR
> -0x1000 GICC_IDR
> 
> Obviously, the region size should be greater than 0x1000.
> So we should make sure to include the GICC_IDR since the kernel will
> access it in some cases.
> 
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-rockchip at lists.infradead.org

applied to a fixes branch for 4.7 with Shawn's review-tag.


Thanks for catching this
Heiko


From shawn.lin at rock-chips.com  Fri May 20 20:55:35 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Sat, 21 May 2016 11:55:35 +0800
Subject: [PATCH 1/2] Documentation: add binding description of Rockchip
 PCIe controller
In-Reply-To: <3930626.4a3xBnzHhK@phil>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740146-7106-1-git-send-email-shawn.lin@rock-chips.com>
 <3930626.4a3xBnzHhK@phil>
Message-ID: <766c3fc9-7e92-6235-76d5-803cc116845a@rock-chips.com>

On 2016/5/20 19:20, Heiko Stuebner wrote:
> Hi Shawn,
>
> Am Freitag, 20. Mai 2016, 18:29:06 schrieb Shawn Lin:
>> This patch add some required and optional properties for Rockchip
>> PCIe controller. Also we add a example for how to use it.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>
>> ---
>>
>>  .../devicetree/bindings/pci/rockchip-pcie.txt      | 93
>> ++++++++++++++++++++++ 1 file changed, 93 insertions(+)
>>  create mode 100644
>> Documentation/devicetree/bindings/pci/rockchip-pcie.txt
>>
>> diff --git a/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
>> b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt new file mode
>> 100644
>> index 0000000..69a0804
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
>> @@ -0,0 +1,93 @@
>> +* Rockchip AXI PCIe Root Port Bridge DT description
>> +
>> +Required properties:
>> +- #address-cells: Address representation for root ports, set to <3>
>> +- #size-cells: Size representation for root ports, set to <2>
>> +- #interrupt-cells: specifies the number of cells needed to encode an
>> +		interrupt source. The value must be 1.
>> +- compatible: Should contain "rockchip,rk3399-pcie"
>> +- reg: Two register ranges as listed in the reg-names property
>> +- reg-names: The first entry must be "axi-base" for the core registers
>> +	The second entry must be "apb-base" for the client pcie registers
>> +- clocks: Must contain an entry for each entry in clock-names.
>> +		See ../clocks/clock-bindings.txt for details.
>> +- clock-names: Must include the following entries:
>> +	- "aclk_pcie"
>> +	- "aclk_perf_pcie"
>> +	- "hclk_pcie"
>> +	- "clk_pciephy_ref"
>
> clock names are always in the scope of the node/driver, so the names could
> easily be "aclk", "aclk-perf", "hclk", "phy".
>
> Although from my cursory-glance at the phy-related code, it looks more like
> it shouldn't be in the pcie-driver itself, but in a an actual phy-driver
> (together with the phy reset and clock)?
>
>> +- interrupts: Three interrupt entries must be specified.
>> +- interrupt-names: Must include the following names
>> +	- "pcie-sys"
>> +	- "pcie-legacy"
>> +	- "pcie-client"
>
> Same as above, names could simply be "sys", "legacy", "client"
>
>
>> +- resets: Must contain five entries for each entry in reset-names.
>> +	   See ../reset/reset.txt for details.
>> +- reset-names: Must include the following names
>> +	- "phy-rst"
>> +	- "core-rst"
>> +	- "mgmt-rst"
>> +	- "mgmt-sticky-rst"
>> +	- "pipe-rst"
>
> and again (= without the "-rst")
>

okay, will simplify clk, int and rst mentioned above.

>
>> +- rockchip,grf: phandle to the syscon managing the "general register
>> files"
>
>> +- pcie-conf: offset of pcie client block for  configuration
>> +- pcie-status: offset of pcie client block for status
>> +- pcie-laneoff: offset of pcie client block for lane
>
> These are GRF offsets (GRF_SOC_CON8, GRF_SOC_CON5_PCIE, GRF_SOC_STATUS1)
> Those registers are generally prone to change (even their layout) for future
> socs and I'd suggest instead of declaring them in the devicetree, move them
> to the per-soc data in the rockchip_pcie_of_match struct.

sure.

>
> But it looks as if they're pretty phy-specific, so see comment about possible
> separate phy driver above.
>
>
>> +- msi-parent: Link to the hardware entity that serves as the Message
>> +- pinctrl-names : The pin control state names
>> +- pinctrl-0: The "default" pinctrl state
>
> I'm not sure if pinctrl-properties need to be described when you don't need
> special handling in the form of additional pin states. The pcie part does
> not do any pin-handling of its own.
>

We need it in prevention of any firmwares change the default state
of #CLKREQ which is useful for ASPM. Also we have a backup pin for
clkreqn called clkreqnb, which should be taken more consideration since
when refering to any one of these two, pinctrl should configure the
bit[14] of GRF_SOC_CON7 automatically. But it is unfortunately beyound
the implementation of pinctrl-rk3399.

BTW, I don't know if we wanna support this action inside the pinctrl
code?

>
>> +- interrupt-map-mask and interrupt-map: standard PCI properties
>> +- interrupt-controller: identifies the node as an interrupt controller
>> +
>> +Optional Property:
>> +- ep-gpios: contain the entry for pre-reset gpio
>> +- num-lanes: number of lanes to use
>> +- assigned-clocks, assigned-clock-parents and assigned-clock-rates:
>> standard +		   clock bindings. See ../clock/clock-bindings.txt
>
> Again that (assigned-clocks handling) is not actual part of the pci-
> controllers actions, but other parts and also described already elsewhere.
>

Basically it does. But this is an alternative choice for pcie-phy to
generate the ref_clk. When we want 100MHz src clk for PLL inside the
pcie-phy?we should add them, otherwise it's taken from xin 24MHz.

This is useful for SI testing or some others special cases. So should we
add it as an option and leave a sample here?

>
> Heiko
>
>
>


-- 
Best Regards
Shawn Lin



From andrea.gelmini at gelma.net  Sat May 21 04:51:09 2016
From: andrea.gelmini at gelma.net (Andrea Gelmini)
Date: Sat, 21 May 2016 13:51:09 +0200
Subject: [PATCH 0114/1529] Fix typo
Message-ID: <20160521115109.5318-1-andrea.gelmini@gelma.net>

Signed-off-by: Andrea Gelmini <andrea.gelmini at gelma.net>
---
 arch/arm/mach-rockchip/pm.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/mach-rockchip/pm.c b/arch/arm/mach-rockchip/pm.c
index bee8c80..309d672 100644
--- a/arch/arm/mach-rockchip/pm.c
+++ b/arch/arm/mach-rockchip/pm.c
@@ -280,7 +280,7 @@ static int rk3288_suspend_init(struct device_node *np)
 
 	rk3288_config_bootdata();
 
-	/* copy resume code and data to bootsram */
+	/* copy resume code and data to bootram */
 	memcpy(rk3288_bootram_base, rockchip_slp_cpu_resume,
 	       rk3288_bootram_sz);
 
-- 
2.8.2.534.g1f66975



From heiko at sntech.de  Sat May 21 05:14:27 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 May 2016 14:14:27 +0200
Subject: [PATCH 0114/1529] Fix typo
In-Reply-To: <20160521115109.5318-1-andrea.gelmini@gelma.net>
References: <20160521115109.5318-1-andrea.gelmini@gelma.net>
Message-ID: <1785036.RoNATgRSre@phil>

Hi Andrea,

Am Samstag, 21. Mai 2016, 13:51:09 schrieb Andrea Gelmini:
> Signed-off-by: Andrea Gelmini <andrea.gelmini at gelma.net>

A series of 1529 patches? That's a bit extreme.

Also in future please use a sane subject line and additionally see comment 
below making the patch not valid.

> ---
>  arch/arm/mach-rockchip/pm.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/arch/arm/mach-rockchip/pm.c b/arch/arm/mach-rockchip/pm.c
> index bee8c80..309d672 100644
> --- a/arch/arm/mach-rockchip/pm.c
> +++ b/arch/arm/mach-rockchip/pm.c
> @@ -280,7 +280,7 @@ static int rk3288_suspend_init(struct device_node *np)
> 
>  	rk3288_config_bootdata();
> 
> -	/* copy resume code and data to bootsram */
> +	/* copy resume code and data to bootram */

this is _not_ a typo, it is sram not regular ram

>  	memcpy(rk3288_bootram_base, rockchip_slp_cpu_resume,
>  	       rk3288_bootram_sz);



From heiko at sntech.de  Sat May 21 06:40:52 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 May 2016 15:40:52 +0200
Subject: [PATCH v2 3/5] ARM: dts: rockchip: move rk3288 io-domain nodes to
 the grf
In-Reply-To: <1459432126-6395-4-git-send-email-heiko@sntech.de>
References: <1459432126-6395-1-git-send-email-heiko@sntech.de>
 <1459432126-6395-4-git-send-email-heiko@sntech.de>
Message-ID: <3043390.x2mOUff8Ni@phil>

Am Donnerstag, 31. M?rz 2016, 15:48:44 schrieb Heiko Stuebner:
> io-voltage control is actually part of the grf, so move the node under the
> newly available grf simple-mfd.
> 
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>

applied for 4.8, but adapted slightly to have the core io-domain nodes centrally in the rk3288.dtsi:

----- 8< -----
From: Heiko Stuebner <heiko at sntech.de>
Date: Sat, 21 May 2016 01:36:17 +0200
Subject: [PATCH v2.1 3/5] ARM: dts: rockchip: move rk3288 io-domain nodes to the grf

io-voltage control is actually part of the grf, so move the node under the
newly available grf simple-mfd.

To minimize duplicate code, the core node and compatible property
gets placed in the core rk3288.dtsi while the individual boards
now only need to enable it and add the necessary supply properties.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
 arch/arm/boot/dts/rk3288-firefly.dtsi   | 31 +++++++++++++++----------------
 arch/arm/boot/dts/rk3288-miqi.dts       | 26 +++++++++++++-------------
 arch/arm/boot/dts/rk3288-popmetal.dts   | 31 +++++++++++++++----------------
 arch/arm/boot/dts/rk3288-rock2-som.dtsi | 31 +++++++++++++++----------------
 arch/arm/boot/dts/rk3288-veyron.dtsi    | 25 ++++++++++++-------------
 arch/arm/boot/dts/rk3288.dtsi           |  5 +++++
 6 files changed, 75 insertions(+), 74 deletions(-)

diff --git a/arch/arm/boot/dts/rk3288-firefly.dtsi b/arch/arm/boot/dts/rk3288-firefly.dtsi
index d6cf9ad..114c90fb 100644
--- a/arch/arm/boot/dts/rk3288-firefly.dtsi
+++ b/arch/arm/boot/dts/rk3288-firefly.dtsi
@@ -64,22 +64,6 @@
 		clock-output-names = "ext_gmac";
 	};
 
-	io_domains: io-domains {
-		compatible = "rockchip,rk3288-io-voltage-domain";
-		rockchip,grf = <&grf>;
-
-		audio-supply = <&vcca_33>;
-		bb-supply = <&vcc_io>;
-		dvp-supply = <&dovdd_1v8>;
-		flash0-supply = <&vcc_flash>;
-		flash1-supply = <&vcc_lan>;
-		gpio30-supply = <&vcc_io>;
-		gpio1830-supply = <&vcc_io>;
-		lcdc-supply = <&vcc_io>;
-		sdcard-supply = <&vccio_sd>;
-		wifi-supply = <&vccio_wl>;
-	};
-
 	ir: ir-receiver {
 		compatible = "gpio-ir-receiver";
 		pinctrl-names = "default";
@@ -397,6 +381,21 @@
 	status = "okay";
 };
 
+&io_domains {
+	status = "okay";
+
+	audio-supply = <&vcca_33>;
+	bb-supply = <&vcc_io>;
+	dvp-supply = <&dovdd_1v8>;
+	flash0-supply = <&vcc_flash>;
+	flash1-supply = <&vcc_lan>;
+	gpio30-supply = <&vcc_io>;
+	gpio1830-supply = <&vcc_io>;
+	lcdc-supply = <&vcc_io>;
+	sdcard-supply = <&vccio_sd>;
+	wifi-supply = <&vccio_wl>;
+};
+
 &pinctrl {
 	pcfg_output_high: pcfg-output-high {
 		output-high;
diff --git a/arch/arm/boot/dts/rk3288-miqi.dts b/arch/arm/boot/dts/rk3288-miqi.dts
index 8643103..2448842 100644
--- a/arch/arm/boot/dts/rk3288-miqi.dts
+++ b/arch/arm/boot/dts/rk3288-miqi.dts
@@ -64,19 +64,6 @@
 		clock-output-names = "ext_gmac";
 	};
 
-	io_domains: io-domains {
-		compatible = "rockchip,rk3288-io-voltage-domain";
-
-		audio-supply = <&vcca_33>;
-		flash0-supply = <&vcc_flash>;
-		flash1-supply = <&vcc_lan>;
-		gpio30-supply = <&vcc_io>;
-		gpio1830-supply = <&vcc_io>;
-		lcdc-supply = <&vcc_io>;
-		sdcard-supply = <&vccio_sd>;
-		wifi-supply = <&vcc_18>;
-	};
-
 	leds {
 		compatible = "gpio-leds";
 
@@ -321,6 +308,19 @@
 	status = "okay";
 };
 
+&io_domains {
+	status = "okay";
+
+	audio-supply = <&vcca_33>;
+	flash0-supply = <&vcc_flash>;
+	flash1-supply = <&vcc_lan>;
+	gpio30-supply = <&vcc_io>;
+	gpio1830-supply = <&vcc_io>;
+	lcdc-supply = <&vcc_io>;
+	sdcard-supply = <&vccio_sd>;
+	wifi-supply = <&vcc_18>;
+};
+
 &pinctrl {
 	pcfg_output_high: pcfg-output-high {
 		output-high;
diff --git a/arch/arm/boot/dts/rk3288-popmetal.dts b/arch/arm/boot/dts/rk3288-popmetal.dts
index 720717b..dda8d25 100644
--- a/arch/arm/boot/dts/rk3288-popmetal.dts
+++ b/arch/arm/boot/dts/rk3288-popmetal.dts
@@ -77,22 +77,6 @@
 		};
 	};
 
-	io_domains: io-domains {
-		compatible = "rockchip,rk3288-io-voltage-domain";
-		rockchip,grf = <&grf>;
-
-		audio-supply = <&vcca_33>;
-		bb-supply = <&vcc_io>;
-		dvp-supply = <&vcc18_dvp>;
-		flash0-supply = <&vcc_flash>;
-		flash1-supply = <&vcc_lan>;
-		gpio30-supply = <&vcc_io>;
-		gpio1830-supply = <&vcc_io>;
-		lcdc-supply = <&vcc_io>;
-		sdcard-supply = <&vccio_sd>;
-		wifi-supply = <&vccio_wl>;
-	};
-
 	ir: ir-receiver {
 		compatible = "gpio-ir-receiver";
 		gpios = <&gpio0 6 GPIO_ACTIVE_LOW>;
@@ -437,6 +421,21 @@
 	status = "okay";
 };
 
+&io_domains {
+	status = "okay";
+
+	audio-supply = <&vcca_33>;
+	bb-supply = <&vcc_io>;
+	dvp-supply = <&vcc18_dvp>;
+	flash0-supply = <&vcc_flash>;
+	flash1-supply = <&vcc_lan>;
+	gpio30-supply = <&vcc_io>;
+	gpio1830-supply = <&vcc_io>;
+	lcdc-supply = <&vcc_io>;
+	sdcard-supply = <&vccio_sd>;
+	wifi-supply = <&vccio_wl>;
+};
+
 &pinctrl {
 	ak8963 {
 		comp_int: comp-int {
diff --git a/arch/arm/boot/dts/rk3288-rock2-som.dtsi b/arch/arm/boot/dts/rk3288-rock2-som.dtsi
index e1ee9f9..bb1f01e 100644
--- a/arch/arm/boot/dts/rk3288-rock2-som.dtsi
+++ b/arch/arm/boot/dts/rk3288-rock2-som.dtsi
@@ -61,22 +61,6 @@
 		clock-output-names = "ext_gmac";
 	};
 
-	io_domains: io-domains {
-		compatible = "rockchip,rk3288-io-voltage-domain";
-		rockchip,grf = <&grf>;
-
-		audio-supply = <&vcc_io>;
-		bb-supply = <&vcc_io>;
-		dvp-supply = <&vcc_18>;
-		flash0-supply = <&vcc_flash>;
-		flash1-supply = <&vccio_pmu>;
-		gpio30-supply = <&vccio_pmu>;
-		gpio1830 = <&vcc_io>;
-		lcdc-supply = <&vcc_io>;
-		sdcard-supply = <&vccio_sd>;
-		wifi-supply = <&vcc_18>;
-	};
-
 	vcc_flash: flash-regulator {
 		compatible = "regulator-fixed";
 		regulator-name = "vcc_sys";
@@ -259,6 +243,21 @@
 	};
 };
 
+&io_domains {
+	status = "okay";
+
+	audio-supply = <&vcc_io>;
+	bb-supply = <&vcc_io>;
+	dvp-supply = <&vcc_18>;
+	flash0-supply = <&vcc_flash>;
+	flash1-supply = <&vccio_pmu>;
+	gpio30-supply = <&vccio_pmu>;
+	gpio1830 = <&vcc_io>;
+	lcdc-supply = <&vcc_io>;
+	sdcard-supply = <&vccio_sd>;
+	wifi-supply = <&vcc_18>;
+};
+
 &pinctrl {
 	pcfg_output_high: pcfg-output-high {
 		output-high;
diff --git a/arch/arm/boot/dts/rk3288-veyron.dtsi b/arch/arm/boot/dts/rk3288-veyron.dtsi
index 5e4c690..3dd2cca 100644
--- a/arch/arm/boot/dts/rk3288-veyron.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron.dtsi
@@ -83,19 +83,6 @@
 		reset-gpios = <&gpio2 9 GPIO_ACTIVE_HIGH>;
 	};
 
-	io_domains: io-domains {
-		compatible = "rockchip,rk3288-io-voltage-domain";
-		rockchip,grf = <&grf>;
-
-		bb-supply = <&vcc33_io>;
-		dvp-supply = <&vcc_18>;
-		flash0-supply = <&vcc18_flashio>;
-		gpio1830-supply = <&vcc33_io>;
-		gpio30-supply = <&vcc33_io>;
-		lcdc-supply = <&vcc33_lcd>;
-		wifi-supply = <&vcc18_wl>;
-	};
-
 	sdio_pwrseq: sdio-pwrseq {
 		compatible = "mmc-pwrseq-simple";
 		clocks = <&rk808 RK808_CLKOUT1>;
@@ -355,6 +342,18 @@
 	i2c-scl-rising-time-ns = <1000>;
 };
 
+&io_domains {
+	status = "okay";
+
+	bb-supply = <&vcc33_io>;
+	dvp-supply = <&vcc_18>;
+	flash0-supply = <&vcc18_flashio>;
+	gpio1830-supply = <&vcc33_io>;
+	gpio30-supply = <&vcc33_io>;
+	lcdc-supply = <&vcc33_lcd>;
+	wifi-supply = <&vcc18_wl>;
+};
+
 &pwm1 {
 	status = "okay";
 };
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 3b44ef3..7fa932f 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -826,6 +826,11 @@
 			#phy-cells = <0>;
 			status = "disabled";
 		};
+
+		io_domains: io-domains {
+			compatible = "rockchip,rk3288-io-voltage-domain";
+			status = "disabled";
+		};
 	};
 
 	wdt: watchdog at ff800000 {
-- 
2.6.4

----- 8< -----



From wsy2220 at gmail.com  Sat May 21 06:46:56 2016
From: wsy2220 at gmail.com (Shuyu Wei)
Date: Sat, 21 May 2016 21:46:56 +0800
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <573E2D0C.604@gmx.de>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com>
 <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com>
 <573E2D0C.604@gmx.de>
Message-ID: <20160521134537.GA25346@debian-dorm>

On Thu, May 19, 2016 at 11:15:56PM +0200, Lino Sanfilippo wrote:
>  drivers/net/ethernet/arc/emac_main.c | 33 +++++++++++++++++----------------
>  1 file changed, 17 insertions(+), 16 deletions(-)
> 
> diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
> index a3a9392..b986499 100644
> --- a/drivers/net/ethernet/arc/emac_main.c
> +++ b/drivers/net/ethernet/arc/emac_main.c
> @@ -162,8 +162,13 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>  		struct sk_buff *skb = tx_buff->skb;
>  		unsigned int info = le32_to_cpu(txbd->info);
>  
> -		if ((info & FOR_EMAC) || !txbd->data || !skb)
> +		if (info & FOR_EMAC) {
> +			/* Make sure we see consistent values for info, skb
> +			 * and data.
> +			 */
> +			rmb();
>  			break;
> +		}
>  
>  		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
>  			stats->tx_errors++;
> @@ -680,35 +685,31 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
>  	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
>  
>  	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
> -
> -	/* Make sure pointer to data buffer is set */
> -	wmb();
> +	priv->tx_buff[*txbd_curr].skb = skb;
>  
>  	skb_tx_timestamp(skb);
>  
> -	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
> -
> -	/* Make sure info word is set */
> +	/* Make sure info is set after data and skb with respect to
> +	 * tx_clean().
> +	 */
>  	wmb();
>  
> -	priv->tx_buff[*txbd_curr].skb = skb;
> +	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
>  
>  	/* Increment index to point to the next BD */
>  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
>  
> -	/* Ensure that tx_clean() sees the new txbd_curr before
> +	/* 1.Ensure that tx_clean() sees the new txbd_curr before
>  	 * checking the queue status. This prevents an unneeded wake
>  	 * of the queue in tx_clean().
> +	 * 2.Ensure that all values are written to RAM and to DMA
> +	 * before hardware is informed.
> +	 * 3.Ensure we see the most recent value for tx_dirty.
>  	 */
> -	smp_mb();
> +	mb();
>  
> -	if (!arc_emac_tx_avail(priv)) {
> +	if (!arc_emac_tx_avail(priv))
>  		netif_stop_queue(ndev);
> -		/* Refresh tx_dirty */
> -		smp_mb();
> -		if (arc_emac_tx_avail(priv))
> -			netif_start_queue(ndev);
> -	}
>  
>  	arc_reg_set(priv, R_STATUS, TXPL_MASK);
> 
> 
Hi Lino,
I applied your patch and tested on my devices, it directly went to
panic. So there must be something wrong.


[   13.084412] rockchip_emac 10204000.ethernet eth0: Link is Up - 100Mbps/Full - flow control rx/tx
[   13.093360] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready
[   13.105915] Unable to handle kernel NULL pointer dereference at virtual address 000000a8
[   13.114173] pgd = c0004000
[   13.117069] [000000a8] *pgd=00000000
[   13.120778] Internal error: Oops: 5 [#1] SMP ARM
[   13.125404] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.6.0+ #88
[   13.131404] Hardware name: Rockchip (Device Tree)
[   13.136108] task: c0804e00 ti: c0800000 task.ti: c0800000
[   13.141515] PC is at __dev_kfree_skb_irq+0xc/0x8c
[   13.146223] LR is at arc_emac_poll+0x94/0x584
[   13.150581] pc : [<c046f588>]    lr : [<c03c5e64>]    psr: 60080113
[   13.150581] sp : c0801d88  ip : c0801da0  fp : c0801d9c
[   13.162046] r10: ee092000  r9 : ee093000  r8 : 00000008
[   13.167268] r7 : 00000000  r6 : 00000004  r5 : f08d0400  r4 : 00000010
[   13.173789] r3 : 00000001  r2 : 00000000  r1 : 00000001  r0 : 00000000
[   13.180312] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
[   13.187441] Control: 10c5387d  Table: 8d24c04a  DAC: 00000051
[   13.193184] Process swapper/0 (pid: 0, stack limit = 0xc0800210)
[   13.199187] Stack: (0xc0801d88 to 0xc0802000)
[   13.203548] 1d80:                   00000010 f08d0400 c0801df4 c0801da0 c03c5e64 c046f588
[   13.211723] 1da0: 00000000 ee0cc154 00000000 ee0924a8 c0801dcc 00000028 c0806614 f08d0408
[   13.219897] 1dc0: ee0922a8 0000007f 00000000 ee0924a8 c03c5dd0 00000028 0000012c fffee77c
[   13.228071] 1de0: c0802100 c0801e18 c0801e54 c0801df8 c0471bfc c03c5ddc c0801e3c c06e5ae8
[   13.236245] 1e00: c08029f4 c08029f4 c083d821 2e86f000 c07486c0 eefb76c0 c0801e18 c0801e18
[   13.244419] 1e20: c0801e20 c0801e20 ee841900 00000000 c080208c c0800000 00000100 00000003
[   13.252594] 1e40: c0802080 40000003 c0801eb4 c0801e58 c012810c c04719fc 00000001 ee808000
[   13.260768] 1e60: c08024a8 00200000 c0802100 fffee77b 0000000a c06017ec c083f940 c07432f8
[   13.268941] 1e80: c0802080 c0801e58 c0801eb4 c07463cc 00000000 00000000 00000001 ee808000
[   13.277115] 1ea0: c08024a8 eefe01c0 c0801ec4 c0801eb8 c01284f8 c0127ff4 c0801eec c0801ec8
[   13.285290] 1ec0: c016504c c012844c c08027b0 f080210c c0801f18 f0802100 f0803100 c08024a8
[   13.293463] 1ee0: c0801f14 c0801ef0 c0101438 c0164ff0 c0107fe4 60080013 ffffffff c0801f4c
[   13.301637] 1f00: c083d6c5 c08024a8 c0801f74 c0801f18 c010c014 c0101404 00000000 eefb4368
[   13.309812] 1f20: 00066cba c0116860 c0800000 c0802454 c083d6c5 00000001 c083d6c5 c08024a8
[   13.317986] 1f40: eefe01c0 c0801f74 c0801f78 c0801f68 c0107fe0 c0107fe4 60080013 ffffffff
[   13.326159] 1f60: 00000051 c016e35c c0801f84 c0801f78 c015cc7c c0107fb0 c0801f9c c0801f88
[   13.334332] 1f80: c015cda8 c015cc60 00000000 c08023c0 c0801fac c0801fa0 c05c4e54 c015cc94
[   13.342507] 1fa0: c0801ff4 c0801fb0 c0700d34 c05c4de4 ffffffff ffffffff 00000000 c0700780
[   13.350680] 1fc0: 00000000 c07268c8 00000000 c083f294 c0802438 c07268c4 c0805f80 6000406a
[   13.358853] 1fe0: 413fc090 00000000 00000000 c0801ff8 60008078 c0700a2c 00000000 00000000
[   13.367017] Backtrace: 
[   13.369489] [<c046f57c>] (__dev_kfree_skb_irq) from [<c03c5e64>] (arc_emac_poll+0x94/0x584)
[   13.377830]  r5:f08d0400 r4:00000010
[   13.381442] [<c03c5dd0>] (arc_emac_poll) from [<c0471bfc>] (net_rx_action+0x20c/0x300)
[   13.389351]  r10:c0801e18 r9:c0802100 r8:fffee77c r7:0000012c r6:00000028 r5:c03c5dd0
[   13.397248]  r4:ee0924a8
[   13.399806] [<c04719f0>] (net_rx_action) from [<c012810c>] (__do_softirq+0x124/0x238)
[   13.407625]  r10:40000003 r9:c0802080 r8:00000003 r7:00000100 r6:c0800000 r5:c080208c
[   13.415520]  r4:00000000
[   13.418073] [<c0127fe8>] (__do_softirq) from [<c01284f8>] (irq_exit+0xb8/0x120)
[   13.425374]  r10:eefe01c0 r9:c08024a8 r8:ee808000 r7:00000001 r6:00000000 r5:00000000
[   13.433267]  r4:c07463cc
[   13.435825] [<c0128440>] (irq_exit) from [<c016504c>] (__handle_domain_irq+0x68/0xbc)
[   13.443655] [<c0164fe4>] (__handle_domain_irq) from [<c0101438>] (gic_handle_irq+0x40/0x7c)
[   13.451994]  r9:c08024a8 r8:f0803100 r7:f0802100 r6:c0801f18 r5:f080210c r4:c08027b0
[   13.459807] [<c01013f8>] (gic_handle_irq) from [<c010c014>] (__irq_svc+0x54/0x70)
[   13.467281] Exception stack(0xc0801f18 to 0xc0801f60)
[   13.472331] 1f00:                                                       00000000 eefb4368
[   13.480505] 1f20: 00066cba c0116860 c0800000 c0802454 c083d6c5 00000001 c083d6c5 c08024a8
[   13.488679] 1f40: eefe01c0 c0801f74 c0801f78 c0801f68 c0107fe0 c0107fe4 60080013 ffffffff
[   13.496845]  r9:c08024a8 r8:c083d6c5 r7:c0801f4c r6:ffffffff r5:60080013 r4:c0107fe4
[   13.504667] [<c0107fa4>] (arch_cpu_idle) from [<c015cc7c>] (default_idle_call+0x28/0x34)
[   13.512758] [<c015cc54>] (default_idle_call) from [<c015cda8>] (cpu_startup_entry+0x120/0x168)
[   13.521369] [<c015cc88>] (cpu_startup_entry) from [<c05c4e54>] (rest_init+0x7c/0x80)
[   13.529102]  r7:c08023c0 r4:00000000
[   13.532715] [<c05c4dd8>] (rest_init) from [<c0700d34>] (start_kernel+0x314/0x320)
[   13.540195] [<c0700a20>] (start_kernel) from [<60008078>] (0x60008078)
[   13.546723] Code: e89da830 e1a0c00d e92dd830 e24cb004 (e59030a8) 
[   13.552874] ---[ end trace b1bc922158d3fc37 ]---
[   13.557511] Kernel panic - not syncing: Fatal exception in interrupt
[   13.563866] CPU2: stopping
[   13.566583] CPU: 2 PID: 0 Comm: swapper/2 Tainted: G      D         4.6.0+ #88
[   13.573798] Hardware name: Rockchip (Device Tree)
[   13.578496] Backtrace: 
[   13.580973] [<c010b2e8>] (dump_backtrace) from [<c010b494>] (show_stack+0x18/0x1c)
[   13.588534]  r7:ee89ff58 r6:60070193 r5:c081d8d8 r4:00000000
[   13.594260] [<c010b47c>] (show_stack) from [<c031eee0>] (dump_stack+0x94/0xa8)
[   13.601484] [<c031ee4c>] (dump_stack) from [<c010cd24>] (handle_IPI+0x17c/0x198)
[   13.608871]  r7:ee89ff58 r6:00000002 r5:00000000 r4:c083f2b0
[   13.614589] [<c010cba8>] (handle_IPI) from [<c0101470>] (gic_handle_irq+0x78/0x7c)
[   13.622149]  r7:f0802100 r6:ee89ff58 r5:f080210c r4:c08027b0
[   13.627865] [<c01013f8>] (gic_handle_irq) from [<c010c014>] (__irq_svc+0x54/0x70)
[   13.635341] Exception stack(0xee89ff58 to 0xee89ffa0)
[   13.640392] ff40:                                                       00000000 eefca368
[   13.648567] ff60: 00015268 c0116860 ee89e000 c0802454 c083d6c5 00000001 c083d6c5 c08024a8
[   13.656742] ff80: 00000000 ee89ffb4 ee89ffb8 ee89ffa8 c0107fe0 c0107fe4 60070013 ffffffff
[   13.664908]  r9:c08024a8 r8:c083d6c5 r7:ee89ff8c r6:ffffffff r5:60070013 r4:c0107fe4
[   13.672731] [<c0107fa4>] (arch_cpu_idle) from [<c015cc7c>] (default_idle_call+0x28/0x34)
[   13.680821] [<c015cc54>] (default_idle_call) from [<c015cda8>] (cpu_startup_entry+0x120/0x168)
[   13.689431] [<c015cc88>] (cpu_startup_entry) from [<c010c968>] (secondary_start_kernel+0x11c/0x120)
[   13.698463]  r7:c083f2c8 r4:c080c700
[   13.702069] [<c010c84c>] (secondary_start_kernel) from [<6010150c>] (0x6010150c)
[   13.709456]  r5:00000051 r4:8e88406a
[   13.713059] CPU1: stopping
[   13.715775] CPU: 1 PID: 0 Comm: swapper/1 Tainted: G      D         4.6.0+ #88
[   13.722990] Hardware name: Rockchip (Device Tree)
[   13.727689] Backtrace: 
[   13.730165] [<c010b2e8>] (dump_backtrace) from [<c010b494>] (show_stack+0x18/0x1c)
[   13.737725]  r7:ee89df58 r6:600f0193 r5:c081d8d8 r4:00000000
[   13.743449] [<c010b47c>] (show_stack) from [<c031eee0>] (dump_stack+0x94/0xa8)
[   13.750672] [<c031ee4c>] (dump_stack) from [<c010cd24>] (handle_IPI+0x17c/0x198)
[   13.758058]  r7:ee89df58 r6:00000001 r5:00000000 r4:c083f2b0
[   13.763775] [<c010cba8>] (handle_IPI) from [<c0101470>] (gic_handle_irq+0x78/0x7c)
[   13.771336]  r7:f0802100 r6:ee89df58 r5:f080210c r4:c08027b0
[   13.777055] [<c01013f8>] (gic_handle_irq) from [<c010c014>] (__irq_svc+0x54/0x70)
[   13.784529] Exception stack(0xee89df58 to 0xee89dfa0)
[   13.789579] df40:                                                       00000000 eefbf368
[   13.797754] df60: 0001c888 c0116860 ee89c000 c0802454 c083d6c5 00000001 c083d6c5 c08024a8
[   13.805929] df80: 00000000 ee89dfb4 ee89dfb8 ee89dfa8 c0107fe0 c0107fe4 600f0013 ffffffff
[   13.814095]  r9:c08024a8 r8:c083d6c5 r7:ee89df8c r6:ffffffff r5:600f0013 r4:c0107fe4
[   13.821913] [<c0107fa4>] (arch_cpu_idle) from [<c015cc7c>] (default_idle_call+0x28/0x34)
[   13.830003] [<c015cc54>] (default_idle_call) from [<c015cda8>] (cpu_startup_entry+0x120/0x168)
[   13.838612] [<c015cc88>] (cpu_startup_entry) from [<c010c968>] (secondary_start_kernel+0x11c/0x120)
[   13.847647]  r7:c083f2c8 r4:c080c700
[   13.851254] [<c010c84c>] (secondary_start_kernel) from [<6010150c>] (0x6010150c)
[   13.858641]  r5:00000051 r4:8e88406a
[   13.862245] CPU3: stopping
[   13.864959] CPU: 3 PID: 0 Comm: swapper/3 Tainted: G      D         4.6.0+ #88
[   13.872175] Hardware name: Rockchip (Device Tree)
[   13.876874] Backtrace: 
[   13.879351] [<c010b2e8>] (dump_backtrace) from [<c010b494>] (show_stack+0x18/0x1c)
[   13.886912]  r7:ee8a1f58 r6:600d0193 r5:c081d8d8 r4:00000000
[   13.892637] [<c010b47c>] (show_stack) from [<c031eee0>] (dump_stack+0x94/0xa8)
[   13.899860] [<c031ee4c>] (dump_stack) from [<c010cd24>] (handle_IPI+0x17c/0x198)
[   13.907246]  r7:ee8a1f58 r6:00000003 r5:00000000 r4:c083f2b0
[   13.912963] [<c010cba8>] (handle_IPI) from [<c0101470>] (gic_handle_irq+0x78/0x7c)
[   13.920524]  r7:f0802100 r6:ee8a1f58 r5:f080210c r4:c08027b0
[   13.926240] [<c01013f8>] (gic_handle_irq) from [<c010c014>] (__irq_svc+0x54/0x70)
[   13.933716] Exception stack(0xee8a1f58 to 0xee8a1fa0)
[   13.938765] 1f40:                                                       00000000 eefd5368
[   13.946940] 1f60: 0001161e c0116860 ee8a0000 c0802454 c083d6c5 00000001 c083d6c5 c08024a8
[   13.955115] 1f80: 00000000 ee8a1fb4 ee8a1fb8 ee8a1fa8 c0107fe0 c0107fe4 600d0013 ffffffff
[   13.963282]  r9:c08024a8 r8:c083d6c5 r7:ee8a1f8c r6:ffffffff r5:600d0013 r4:c0107fe4
[   13.971100] [<c0107fa4>] (arch_cpu_idle) from [<c015cc7c>] (default_idle_call+0x28/0x34)
[   13.979190] [<c015cc54>] (default_idle_call) from [<c015cda8>] (cpu_startup_entry+0x120/0x168)
[   13.987800] [<c015cc88>] (cpu_startup_entry) from [<c010c968>] (secondary_start_kernel+0x11c/0x120)
[   13.996834]  r7:c083f2c8 r4:c080c700
[   14.000441] [<c010c84c>] (secondary_start_kernel) from [<6010150c>] (0x6010150c)
[   14.007828]  r5:00000051 r4:8e88406a
[   14.011435] ---[ end Kernel panic - not syncing: Fatal exception in interrupt



From heiko at sntech.de  Sat May 21 06:55:06 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 May 2016 15:55:06 +0200
Subject: [PATCH v2 4/5] arm64: dts: rockchip: make rk3368 grf syscons
 simple-mfds as well
In-Reply-To: <1459432126-6395-5-git-send-email-heiko@sntech.de>
References: <1459432126-6395-1-git-send-email-heiko@sntech.de>
 <1459432126-6395-5-git-send-email-heiko@sntech.de>
Message-ID: <2597247.kfueRAYi3v@phil>

Am Donnerstag, 31. M?rz 2016, 15:48:45 schrieb Heiko Stuebner:
> The general register files do contain a lot of separate functions and
> while some really are only registers with a lot of different 1-bit
> settings, there are also a lot of them containing some bigger function
> blocks. To be able to define these as sub-devices, make them simple-mfds.
> 
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> Tested-by: David Wu <david.wu at rock-chips.com>

applied for 4.8


From wsy2220 at gmail.com  Sat May 21 09:09:10 2016
From: wsy2220 at gmail.com (Shuyu Wei)
Date: Sun, 22 May 2016 00:09:10 +0800
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160520003145.GA22420@electric-eye.fr.zoreil.com>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com>
 <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com>
 <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
Message-ID: <20160521160910.GA14945@debian-dorm>

Looks like I got it wrong in the first place.

priv->tx_buff is not for the device, so there's no need to move it.
The race has been fixed by commit c278c253f3d9, I forgot to check
it out. That's my fault.

I do find another problem. We need to use a barrier to make sure
skb_tx_timestamp() is called before setting the FOR_EMAC flag.

According to the comment(include/linux/skbuff.h):
>/**
> * skb_tx_timestamp() - Driver hook for transmit timestamping
> *
> * Ethernet MAC Drivers should call this function in their hard_xmit()
> * function immediately before giving the sk_buff to the MAC hardware.
> *
> * Specifically, one should make absolutely sure that this function is
> * called before TX completion of this packet can trigger.  Otherwise
> * the packet could potentially already be freed.
> *
> * @skb: A socket buffer.
> */

---

diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index a3a9392..c2447b0 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -686,6 +686,9 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
 
        skb_tx_timestamp(skb);
 
+       /* Make sure timestamp is set */
+       smp_wmb();
+
        *info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
        /* Make sure info word is set */



From heiko at sntech.de  Sat May 21 09:52:07 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 May 2016 18:52:07 +0200
Subject: [PATCH v2 5/5] arm64: dts: rockchip: add rk3368-r88 iodomains
In-Reply-To: <1459432126-6395-6-git-send-email-heiko@sntech.de>
References: <1459432126-6395-1-git-send-email-heiko@sntech.de>
 <1459432126-6395-6-git-send-email-heiko@sntech.de>
Message-ID: <1656719.1xsq0kaqYf@phil>

Am Donnerstag, 31. M?rz 2016, 15:48:46 schrieb Heiko Stuebner:
> Add the supply-links according to the R88 schematics.
> 
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>

going to rework this one a bit and make it part of a new series.


From romieu at fr.zoreil.com  Sat May 21 12:47:33 2016
From: romieu at fr.zoreil.com (Francois Romieu)
Date: Sat, 21 May 2016 21:47:33 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160521160910.GA14945@debian-dorm>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com>
 <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com>
 <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm>
Message-ID: <20160521194733.GA30557@electric-eye.fr.zoreil.com>

Shuyu Wei <wsy2220 at gmail.com> :
[...]
> diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
> index a3a9392..c2447b0 100644
> --- a/drivers/net/ethernet/arc/emac_main.c
> +++ b/drivers/net/ethernet/arc/emac_main.c
> @@ -686,6 +686,9 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
>  
>         skb_tx_timestamp(skb);
>  
> +       /* Make sure timestamp is set */
> +       smp_wmb();

Should be dma_wmb() (see davem's message).

It's completely unrelated to SMP.

-- 
Ueimor


From heiko at sntech.de  Sat May 21 14:23:48 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 May 2016 23:23:48 +0200
Subject: [PATCH 3/3] arm64: dts: rockchip: add rk3399 io-domain core nodes
In-Reply-To: <1463865828-14583-1-git-send-email-heiko@sntech.de>
References: <1463865828-14583-1-git-send-email-heiko@sntech.de>
Message-ID: <1463865828-14583-4-git-send-email-heiko@sntech.de>

Add the core io-domain nodes to grf and pmugrf which individual
boards than just have to enable and add the necessary supplies to.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index a6a60fa..12acae6 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -407,6 +407,11 @@
 		reg = <0x0 0xff320000 0x0 0x1000>;
 		#address-cells = <1>;
 		#size-cells = <1>;
+
+		pmu_io_domains: io-domains {
+			compatible = "rockchip,rk3399-pmu-io-voltage-domain";
+			status = "disabled";
+		};
 	};
 
 	spi3: spi at ff350000 {
@@ -517,6 +522,11 @@
 		#address-cells = <1>;
 		#size-cells = <1>;
 
+		io_domains: io-domains {
+			compatible = "rockchip,rk3399-io-voltage-domain";
+			status = "disabled";
+		};
+
 		emmc_phy: phy at f780 {
 			compatible = "rockchip,rk3399-emmc-phy";
 			reg = <0xf780 0x24>;
-- 
2.6.4



From heiko at sntech.de  Sat May 21 14:23:47 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 May 2016 23:23:47 +0200
Subject: [PATCH 2/3] arm64: dts: rockchip: add rk3368-r88 iodomains
In-Reply-To: <1463865828-14583-1-git-send-email-heiko@sntech.de>
References: <1463865828-14583-1-git-send-email-heiko@sntech.de>
Message-ID: <1463865828-14583-3-git-send-email-heiko@sntech.de>

Add the supply-links according to the R88 schematics.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
 arch/arm64/boot/dts/rockchip/rk3368-r88.dts | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
index b56b720..82a32e5 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3368-r88.dts
@@ -236,6 +236,15 @@
 	};
 };
 
+&io_domains {
+	status = "ok";
+
+	audio-supply = <&vcc_io>;
+	gpio30-supply = <&vcc_io>;
+	gpio1830-supply = <&vcc_io>;
+	wifi-supply = <&vccio_wl>;
+};
+
 &sdio0 {
 	assigned-clocks = <&cru SCLK_SDIO0>;
 	assigned-clock-parents = <&cru PLL_CPLL>;
@@ -329,6 +338,13 @@
 	};
 };
 
+&pmu_io_domains {
+	status = "okay";
+
+	pmu-supply = <&vcc_io>;
+	vop-supply = <&vcc_io>;
+};
+
 &saradc {
 	vref-supply = <&vcc_18>;
 	status = "okay";
-- 
2.6.4



From heiko at sntech.de  Sat May 21 14:23:46 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 May 2016 23:23:46 +0200
Subject: [PATCH 1/3] arm64: dts: rockchip: add rk3368 io-domain core nodes
In-Reply-To: <1463865828-14583-1-git-send-email-heiko@sntech.de>
References: <1463865828-14583-1-git-send-email-heiko@sntech.de>
Message-ID: <1463865828-14583-2-git-send-email-heiko@sntech.de>

Add the core io-domain nodes to grf and pmugrf which individual
boards than just have to enable and add the necessary supplies to.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
 arch/arm64/boot/dts/rockchip/rk3368.dtsi | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3368.dtsi b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
index 4fb8484..58c2585 100644
--- a/arch/arm64/boot/dts/rockchip/rk3368.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3368.dtsi
@@ -634,6 +634,11 @@
 	pmugrf: syscon at ff738000 {
 		compatible = "rockchip,rk3368-pmugrf", "syscon", "simple-mfd";
 		reg = <0x0 0xff738000 0x0 0x1000>;
+
+		pmu_io_domains: io-domains {
+			compatible = "rockchip,rk3368-pmu-io-voltage-domain";
+			status = "disabled";
+		};
 	};
 
 	cru: clock-controller at ff760000 {
@@ -647,6 +652,11 @@
 	grf: syscon at ff770000 {
 		compatible = "rockchip,rk3368-grf", "syscon", "simple-mfd";
 		reg = <0x0 0xff770000 0x0 0x1000>;
+
+		io_domains: io-domains {
+			compatible = "rockchip,rk3368-io-voltage-domain";
+			status = "disabled";
+		};
 	};
 
 	wdt: watchdog at ff800000 {
-- 
2.6.4



From heiko at sntech.de  Sat May 21 14:23:45 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sat, 21 May 2016 23:23:45 +0200
Subject: [PATCH 0/3] arm64: dts: rockchip: add io-domain support for rk3368
 and rk3399
Message-ID: <1463865828-14583-1-git-send-email-heiko@sntech.de>

This adds the core io-domain nodes for both the rk3368 and rk3399
as well as the actual supplies on the rk3368-r88 board.

This of course needs
    PM / AVS: rockchip-io: make io-domains a child of the GRF
that went into mainline during the 4.7 merge window.

Heiko Stuebner (3):
  arm64: dts: rockchip: add rk3368 io-domain core nodes
  arm64: dts: rockchip: add rk3368-r88 iodomains
  arm64: dts: rockchip: add rk3399 io-domain core nodes

 arch/arm64/boot/dts/rockchip/rk3368-r88.dts | 16 ++++++++++++++++
 arch/arm64/boot/dts/rockchip/rk3368.dtsi    | 10 ++++++++++
 arch/arm64/boot/dts/rockchip/rk3399.dtsi    | 10 ++++++++++
 3 files changed, 36 insertions(+)

-- 
2.6.4



From LinoSanfilippo at gmx.de  Sat May 21 15:58:55 2016
From: LinoSanfilippo at gmx.de (Lino Sanfilippo)
Date: Sun, 22 May 2016 00:58:55 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160521160910.GA14945@debian-dorm>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com> <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com> <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm>
Message-ID: <5740E82F.8040903@gmx.de>


On 21.05.2016 18:09, Shuyu Wei wrote:
> Looks like I got it wrong in the first place.
> 
> priv->tx_buff is not for the device, so there's no need to move it.
> The race has been fixed by commit c278c253f3d9, I forgot to check
> it out. That's my fault.
> 
> I do find another problem. We need to use a barrier to make sure
> skb_tx_timestamp() is called before setting the FOR_EMAC flag.
> 

Shuyu,

Could you please test the patch below? I implemented a new approach
in which tx_clean uses txbd_curr to determine if there are more 
descriptors to check or if the loop can be left. 
Memory barriers on both sides (xmit and clean) should ensure that 
SKB and info are only accessed if they are valid.
I also hope that skb_tx_timestamp is not an issue any more.


BTW: concerning get_maintainer Alexander Kochetkov should be CCed for
modifications in this area, so thats what I do hereby.

--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -162,7 +162,13 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 		struct sk_buff *skb = tx_buff->skb;
 		unsigned int info = le32_to_cpu(txbd->info);
 
-		if ((info & FOR_EMAC) || !txbd->data || !skb)
+		if (info & FOR_EMAC)
+			break;
+
+		/* Make sure curr pointer is consistent with info */
+		rmb();
+
+		if (*txbd_dirty == priv->txbd_curr)
 			break;
 
 		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
@@ -195,8 +201,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 		*txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;
 	}
 
-	/* Ensure that txbd_dirty is visible to tx() before checking
-	 * for queue stopped.
+	/* Ensure that txbd_dirty is visible to tx() and we see the most recent
+	 * value for txbd_curr.
 	 */
 	smp_mb();
 
@@ -680,35 +686,29 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
 	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
 
 	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
-
-	/* Make sure pointer to data buffer is set */
-	wmb();
+	priv->tx_buff[*txbd_curr].skb = skb;
 
 	skb_tx_timestamp(skb);
 
 	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
-	/* Make sure info word is set */
+	/* 1. Make sure that with respect to tx_clean everything is set up
+	 * properly before we advance txbd_curr.
+	 * 2. Make sure writes to DMA descriptors are completed before we inform
+	 * the hardware.
+	 */
 	wmb();
 
-	priv->tx_buff[*txbd_curr].skb = skb;
-
 	/* Increment index to point to the next BD */
 	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
 
-	/* Ensure that tx_clean() sees the new txbd_curr before
-	 * checking the queue status. This prevents an unneeded wake
-	 * of the queue in tx_clean().
+	/* Ensure we see the most recent value of txbd_dirty and tx_clean() sees
+	 * the updated value of txbd_curr.
 	 */
 	smp_mb();
 
-	if (!arc_emac_tx_avail(priv)) {
+	if (!arc_emac_tx_avail(priv))
 		netif_stop_queue(ndev);
-		/* Refresh tx_dirty */
-		smp_mb();
-		if (arc_emac_tx_avail(priv))
-			netif_start_queue(ndev);
-	}
 
 	arc_reg_set(priv, R_STATUS, TXPL_MASK);
 
-- 
1.9.1



From LinoSanfilippo at gmx.de  Sat May 21 16:04:42 2016
From: LinoSanfilippo at gmx.de (Lino Sanfilippo)
Date: Sun, 22 May 2016 01:04:42 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160521194733.GA30557@electric-eye.fr.zoreil.com>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com> <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com> <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm>
 <20160521194733.GA30557@electric-eye.fr.zoreil.com>
Message-ID: <5740E98A.5050803@gmx.de>

On 21.05.2016 21:47, Francois Romieu wrote:
> Shuyu Wei <wsy2220 at gmail.com> :
> [...]
>> diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
>> index a3a9392..c2447b0 100644
>> --- a/drivers/net/ethernet/arc/emac_main.c
>> +++ b/drivers/net/ethernet/arc/emac_main.c
>> @@ -686,6 +686,9 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
>>  
>>         skb_tx_timestamp(skb);
>>  
>> +       /* Make sure timestamp is set */
>> +       smp_wmb();
> 
> Should be dma_wmb() (see davem's message).
> 
> It's completely unrelated to SMP.
> 

Its also completely unrelated to dma so I doubt that this is what davem meant.
As far as I understood he was referring to the dma descriptor.

Lino


From wsy2220 at gmail.com  Sun May 22 02:17:42 2016
From: wsy2220 at gmail.com (Shuyu Wei)
Date: Sun, 22 May 2016 17:17:42 +0800
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <5740E82F.8040903@gmx.de>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com>
 <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com>
 <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm> <5740E82F.8040903@gmx.de>
Message-ID: <20160522091742.GA8681@debian-dorm>

On Sun, May 22, 2016 at 12:58:55AM +0200, Lino Sanfilippo wrote:
> --- a/drivers/net/ethernet/arc/emac_main.c
> +++ b/drivers/net/ethernet/arc/emac_main.c
> @@ -162,7 +162,13 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>  		struct sk_buff *skb = tx_buff->skb;
>  		unsigned int info = le32_to_cpu(txbd->info);
>  
> -		if ((info & FOR_EMAC) || !txbd->data || !skb)
> +		if (info & FOR_EMAC)
> +			break;
> +
> +		/* Make sure curr pointer is consistent with info */
> +		rmb();
> +
> +		if (*txbd_dirty == priv->txbd_curr)
>  			break;
>  
>  		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
> @@ -195,8 +201,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>  		*txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;
>  	}
>  
> -	/* Ensure that txbd_dirty is visible to tx() before checking
> -	 * for queue stopped.
> +	/* Ensure that txbd_dirty is visible to tx() and we see the most recent
> +	 * value for txbd_curr.
>  	 */
>  	smp_mb();
>  
> @@ -680,35 +686,29 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
>  	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
>  
>  	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
> -
> -	/* Make sure pointer to data buffer is set */
> -	wmb();
> +	priv->tx_buff[*txbd_curr].skb = skb;
>  
>  	skb_tx_timestamp(skb);
>  
>  	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
>  
> -	/* Make sure info word is set */
> +	/* 1. Make sure that with respect to tx_clean everything is set up
> +	 * properly before we advance txbd_curr.
> +	 * 2. Make sure writes to DMA descriptors are completed before we inform
> +	 * the hardware.
> +	 */
>  	wmb();
>  
> -	priv->tx_buff[*txbd_curr].skb = skb;
> -
>  	/* Increment index to point to the next BD */
>  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
>  
> -	/* Ensure that tx_clean() sees the new txbd_curr before
> -	 * checking the queue status. This prevents an unneeded wake
> -	 * of the queue in tx_clean().
> +	/* Ensure we see the most recent value of txbd_dirty and tx_clean() sees
> +	 * the updated value of txbd_curr.
>  	 */
>  	smp_mb();
>  
> -	if (!arc_emac_tx_avail(priv)) {
> +	if (!arc_emac_tx_avail(priv))
>  		netif_stop_queue(ndev);
> -		/* Refresh tx_dirty */
> -		smp_mb();
> -		if (arc_emac_tx_avail(priv))
> -			netif_start_queue(ndev);
> -	}
>  
>  	arc_reg_set(priv, R_STATUS, TXPL_MASK);
>  

Hi Lino,

I tested this patch, it still got panic under stress.
Just wget 2 large files simultaneously and it failed.

Looks like the problem comes from the if statement in tx_clean().
I changed your patch to use 

-               if (info & FOR_EMAC)
+               if ((info & FOR_EMAC) || !txbd->data || !skb)

and it worked. 

After further test, my patch to barrier timestamp() didn't work.
Just like the original code in the tree, the emac still got stuck under
high load, even if I changed the smp_wmb() to dma_wmb(). So the original
code do have race somewhere. 

I'm new to kernel development, and still trying to understand how memory
barrier works and why Francois' fix worked. Please be patient with me :-).

---

[  138.501355] Unable to handle kernel NULL pointer dereference at virtual address 000000a8
[  138.509482] pgd = c0004000
[  138.512200] [000000a8] *pgd=00000000
[  138.515850] Internal error: Oops: 5 [#1] SMP ARM
[  138.520476] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 4.6.0+ #98
[  138.526477] Hardware name: Rockchip (Device Tree)
[  138.531180] task: c0804e00 ti: c0800000 task.ti: c0800000
[  138.536588] PC is at __dev_kfree_skb_irq+0xc/0x8c
[  138.541295] LR is at arc_emac_poll+0x94/0x594
[  138.545653] pc : [<c046f590>]    lr : [<c03c5e64>]    psr: 60050113
[  138.545653] sp : c0801d88  ip : c0801da0  fp : c0801d9c
[  138.557118] r10: ee0a0000  r9 : ee0a1000  r8 : 000001f8
[  138.562340] r7 : 00000000  r6 : 000000fc  r5 : f08d0400  r4 : 000003f0
[  138.568861] r3 : 00000001  r2 : 00000042  r1 : 00000001  r0 : 00000000
[  138.575385] Flags: nZCv  IRQs on  FIQs on  Mode SVC_32  ISA ARM  Segment none
[  138.582515] Control: 10c5387d  Table: 8da4004a  DAC: 00000051
[  138.588256] Process swapper/0 (pid: 0, stack limit = 0xc0800210)
[  138.594258] Stack: (0xc0801d88 to 0xc0802000)
[  138.598617] 1d80:                   000003f0 f08d0400 c0801df4 c0801da0 c03c5e64 c046f590
[  138.606794] 1da0: 00000000 c0171050 c0801ddc ee0a04a8 c016504c 00000028 c0806614 f08d05f8
[  138.614969] 1dc0: ee0a02a8 00000080 f0803100 ee0a04a8 c03c5dd0 00000028 0000012c ffff623d
[  138.623144] 1de0: c0802100 c0801e18 c0801e54 c0801df8 c0471c04 c03c5ddc c0801eb4 c06e5ae8
[  138.631318] 1e00: c08029f4 c08029f4 c083d821 2e86f000 c07486c0 eefb76c0 c0801e18 c0801e18
[  138.639492] 1e20: c0801e20 c0801e20 00000003 00000000 c080208c c0800000 00000100 00000003
[  138.647666] 1e40: c0802080 40000003 c0801eb4 c0801e58 c012810c c0471a04 00000001 ee808000
[  138.655841] 1e60: c08024a8 00200000 c0802100 ffff623c 00000009 c06017ec c083f940 c07432f8
[  138.664015] 1e80: c0802080 c0801e58 c0801eb4 c07463cc 00000000 00000000 00000001 ee808000
[  138.672188] 1ea0: c08024a8 eefe01c0 c0801ec4 c0801eb8 c01284f8 c0127ff4 c0801eec c0801ec8
[  138.680363] 1ec0: c016504c c012844c c08027b0 f080210c c0801f18 f0802100 f0803100 c08024a8
[  138.688536] 1ee0: c0801f14 c0801ef0 c0101438 c0164ff0 c0107fe4 60050013 ffffffff c0801f4c
[  138.696710] 1f00: c083d6c5 c08024a8 c0801f74 c0801f18 c010c014 c0101404 00000000 eefb4368
[  138.704884] 1f20: 006b18d8 c0116860 c0800000 c0802454 c083d6c5 00000001 c083d6c5 c08024a8
[  138.713059] 1f40: eefe01c0 c0801f74 c0801f78 c0801f68 c0107fe0 c0107fe4 60050013 ffffffff
[  138.721232] 1f60: 00000051 c016e35c c0801f84 c0801f78 c015cc7c c0107fb0 c0801f9c c0801f88
[  138.729406] 1f80: c015cda8 c015cc60 00000000 c08023c0 c0801fac c0801fa0 c05c4e54 c015cc94
[  138.737580] 1fa0: c0801ff4 c0801fb0 c0700d34 c05c4de4 ffffffff ffffffff 00000000 c0700780
[  138.745754] 1fc0: 00000000 c07268c8 00000000 c083f294 c0802438 c07268c4 c0805f80 6000406a
[  138.753928] 1fe0: 413fc090 00000000 00000000 c0801ff8 60008078 c0700a2c 00000000 00000000
[  138.762093] Backtrace: 
[  138.764567] [<c046f584>] (__dev_kfree_skb_irq) from [<c03c5e64>] (arc_emac_poll+0x94/0x594)
[  138.772908]  r5:f08d0400 r4:000003f0
[  138.776522] [<c03c5dd0>] (arc_emac_poll) from [<c0471c04>] (net_rx_action+0x20c/0x300)
[  138.784430]  r10:c0801e18 r9:c0802100 r8:ffff623d r7:0000012c r6:00000028 r5:c03c5dd0
[  138.792324]  r4:ee0a04a8
[  138.794882] [<c04719f8>] (net_rx_action) from [<c012810c>] (__do_softirq+0x124/0x238)
[  138.802704]  r10:40000003 r9:c0802080 r8:00000003 r7:00000100 r6:c0800000 r5:c080208c
[  138.810596]  r4:00000000
[  138.813150] [<c0127fe8>] (__do_softirq) from [<c01284f8>] (irq_exit+0xb8/0x120)
[  138.820449]  r10:eefe01c0 r9:c08024a8 r8:ee808000 r7:00000001 r6:00000000 r5:00000000
[  138.828342]  r4:c07463cc
[  138.830899] [<c0128440>] (irq_exit) from [<c016504c>] (__handle_domain_irq+0x68/0xbc)
[  138.838729] [<c0164fe4>] (__handle_domain_irq) from [<c0101438>] (gic_handle_irq+0x40/0x7c)
[  138.847069]  r9:c08024a8 r8:f0803100 r7:f0802100 r6:c0801f18 r5:f080210c r4:c08027b0
[  138.854882] [<c01013f8>] (gic_handle_irq) from [<c010c014>] (__irq_svc+0x54/0x70)
[  138.862358] Exception stack(0xc0801f18 to 0xc0801f60)
[  138.867407] 1f00:                                                       00000000 eefb4368
[  138.875583] 1f20: 006b18d8 c0116860 c0800000 c0802454 c083d6c5 00000001 c083d6c5 c08024a8
[  138.883757] 1f40: eefe01c0 c0801f74 c0801f78 c0801f68 c0107fe0 c0107fe4 60050013 ffffffff
[  138.891924]  r9:c08024a8 r8:c083d6c5 r7:c0801f4c r6:ffffffff r5:60050013 r4:c0107fe4
[  138.899749] [<c0107fa4>] (arch_cpu_idle) from [<c015cc7c>] (default_idle_call+0x28/0x34)
[  138.907839] [<c015cc54>] (default_idle_call) from [<c015cda8>] (cpu_startup_entry+0x120/0x168)
[  138.916451] [<c015cc88>] (cpu_startup_entry) from [<c05c4e54>] (rest_init+0x7c/0x80)
[  138.924185]  r7:c08023c0 r4:00000000
[  138.927799] [<c05c4dd8>] (rest_init) from [<c0700d34>] (start_kernel+0x314/0x320)
[  138.935279] [<c0700a20>] (start_kernel) from [<60008078>] (0x60008078)
[  138.941807] Code: e89da830 e1a0c00d e92dd830 e24cb004 (e59030a8) 
[  138.947973] ---[ end trace c64a970fa34feb9a ]---
[  138.952614] Kernel panic - not syncing: Fatal exception in interrupt
[  138.958978] CPU3: stopping
[  138.961697] CPU: 3 PID: 0 Comm: swapper/3 Tainted: G      D         4.6.0+ #98
[  138.968913] Hardware name: Rockchip (Device Tree)
[  138.973613] Backtrace: 
[  138.976095] [<c010b2e8>] (dump_backtrace) from [<c010b494>] (show_stack+0x18/0x1c)
[  138.983658]  r7:ee8a1f58 r6:60070193 r5:c081d8d8 r4:00000000
[  138.989385] [<c010b47c>] (show_stack) from [<c031eee0>] (dump_stack+0x94/0xa8)
[  138.996610] [<c031ee4c>] (dump_stack) from [<c010cd24>] (handle_IPI+0x17c/0x198)
[  139.003998]  r7:ee8a1f58 r6:00000003 r5:00000000 r4:c083f2b0
[  139.009716] [<c010cba8>] (handle_IPI) from [<c0101470>] (gic_handle_irq+0x78/0x7c)
[  139.017277]  r7:f0802100 r6:ee8a1f58 r5:f080210c r4:c08027b0
[  139.022996] [<c01013f8>] (gic_handle_irq) from [<c010c014>] (__irq_svc+0x54/0x70)
[  139.030471] Exception stack(0xee8a1f58 to 0xee8a1fa0)
[  139.035521] 1f40:                                                       00000000 eefd5368
[  139.043697] 1f60: 00d5d590 c0116860 ee8a0000 c0802454 c083d6c5 00000001 c083d6c5 c08024a8
[  139.051872] 1f80: 00000000 ee8a1fb4 ee8a1fb8 ee8a1fa8 c0107fe0 c0107fe4 60070013 ffffffff
[  139.060039]  r9:c08024a8 r8:c083d6c5 r7:ee8a1f8c r6:ffffffff r5:60070013 r4:c0107fe4
[  139.067856] [<c0107fa4>] (arch_cpu_idle) from [<c015cc7c>] (default_idle_call+0x28/0x34)
[  139.075948] [<c015cc54>] (default_idle_call) from [<c015cda8>] (cpu_startup_entry+0x120/0x168)
[  139.084557] [<c015cc88>] (cpu_startup_entry) from [<c010c968>] (secondary_start_kernel+0x11c/0x120)
[  139.093591]  r7:c083f2c8 r4:c080c700
[  139.097197] [<c010c84c>] (secondary_start_kernel) from [<6010150c>] (0x6010150c)
[  139.104583]  r5:00000051 r4:8e88406a
[  139.108186] CPU2: stopping
[  139.110903] CPU: 2 PID: 0 Comm: swapper/2 Tainted: G      D         4.6.0+ #98
[  139.118118] Hardware name: Rockchip (Device Tree)
[  139.122817] Backtrace: 
[  139.125293] [<c010b2e8>] (dump_backtrace) from [<c010b494>] (show_stack+0x18/0x1c)
[  139.132855]  r7:ee89ff58 r6:60030193 r5:c081d8d8 r4:00000000
[  139.138581] [<c010b47c>] (show_stack) from [<c031eee0>] (dump_stack+0x94/0xa8)
[  139.145803] [<c031ee4c>] (dump_stack) from [<c010cd24>] (handle_IPI+0x17c/0x198)
[  139.153191]  r7:ee89ff58 r6:00000002 r5:00000000 r4:c083f2b0
[  139.158909] [<c010cba8>] (handle_IPI) from [<c0101470>] (gic_handle_irq+0x78/0x7c)
[  139.166470]  r7:f0802100 r6:ee89ff58 r5:f080210c r4:c08027b0
[  139.172188] [<c01013f8>] (gic_handle_irq) from [<c010c014>] (__irq_svc+0x54/0x70)
[  139.179664] Exception stack(0xee89ff58 to 0xee89ffa0)
[  139.184714] ff40:                                                       00000000 eefca368
[  139.192890] ff60: 00c866ca c0116860 ee89e000 c0802454 c083d6c5 00000001 c083d6c5 c08024a8
[  139.201064] ff80: 00000000 ee89ffb4 ee89ffb8 ee89ffa8 c0107fe0 c0107fe4 60030013 ffffffff
[  139.209231]  r9:c08024a8 r8:c083d6c5 r7:ee89ff8c r6:ffffffff r5:60030013 r4:c0107fe4
[  139.217051] [<c0107fa4>] (arch_cpu_idle) from [<c015cc7c>] (default_idle_call+0x28/0x34)
[  139.225141] [<c015cc54>] (default_idle_call) from [<c015cda8>] (cpu_startup_entry+0x120/0x168)
[  139.233750] [<c015cc88>] (cpu_startup_entry) from [<c010c968>] (secondary_start_kernel+0x11c/0x120)
[  139.242784]  r7:c083f2c8 r4:c080c700
[  139.246391] [<c010c84c>] (secondary_start_kernel) from [<6010150c>] (0x6010150c)
[  139.253777]  r5:00000051 r4:8e88406a
[  139.257378] CPU1: stopping
[  139.260095] CPU: 1 PID: 0 Comm: swapper/1 Tainted: G      D         4.6.0+ #98
[  139.267309] Hardware name: Rockchip (Device Tree)
[  139.272009] Backtrace: 
[  139.274484] [<c010b2e8>] (dump_backtrace) from [<c010b494>] (show_stack+0x18/0x1c)
[  139.282046]  r7:ee89df58 r6:60070193 r5:c081d8d8 r4:00000000
[  139.287771] [<c010b47c>] (show_stack) from [<c031eee0>] (dump_stack+0x94/0xa8)
[  139.294994] [<c031ee4c>] (dump_stack) from [<c010cd24>] (handle_IPI+0x17c/0x198)
[  139.302381]  r7:ee89df58 r6:00000001 r5:00000000 r4:c083f2b0
[  139.308100] [<c010cba8>] (handle_IPI) from [<c0101470>] (gic_handle_irq+0x78/0x7c)
[  139.315661]  r7:f0802100 r6:ee89df58 r5:f080210c r4:c08027b0
[  139.321376] [<c01013f8>] (gic_handle_irq) from [<c010c014>] (__irq_svc+0x54/0x70)
[  139.328850] Exception stack(0xee89df58 to 0xee89dfa0)
[  139.333901] df40:                                                       00000000 eefbf368
[  139.342077] df60: 00c9fb38 c0116860 ee89c000 c0802454 c083d6c5 00000001 c083d6c5 c08024a8
[  139.350252] df80: 00000000 ee89dfb4 ee89dfb8 ee89dfa8 c0107fe0 c0107fe4 60070013 ffffffff
[  139.358418]  r9:c08024a8 r8:c083d6c5 r7:ee89df8c r6:ffffffff r5:60070013 r4:c0107fe4
[  139.366235] [<c0107fa4>] (arch_cpu_idle) from [<c015cc7c>] (default_idle_call+0x28/0x34)
[  139.374327] [<c015cc54>] (default_idle_call) from [<c015cda8>] (cpu_startup_entry+0x120/0x168)
[  139.382935] [<c015cc88>] (cpu_startup_entry) from [<c010c968>] (secondary_start_kernel+0x11c/0x120)
[  139.391969]  r7:c083f2c8 r4:c080c700
[  139.395575] [<c010c84c>] (secondary_start_kernel) from [<6010150c>] (0x6010150c)
[  139.402961]  r5:00000051 r4:8e88406a
[  139.406570] ---[ end Kernel panic - not syncing: Fatal exception in interrupt


From heiko at sntech.de  Sun May 22 02:27:34 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Sun, 22 May 2016 11:27:34 +0200
Subject: [PATCH 05/54] MAINTAINERS: Add file patterns for rockchip device
 tree bindings
In-Reply-To: <1463907991-7916-6-git-send-email-geert@linux-m68k.org>
References: <1463907991-7916-1-git-send-email-geert@linux-m68k.org>
 <1463907991-7916-6-git-send-email-geert@linux-m68k.org>
Message-ID: <1575416.jfSztnP7S8@phil>

Hi Geert,

Am Sonntag, 22. Mai 2016, 11:05:42 schrieb Geert Uytterhoeven:
> Submitters of device tree binding documentation may forget to CC
> the subsystem maintainer if this is missing.

The "N:	rockchip" line at the bottom of the block catches this nicely 
already (also just verified with a get_maintainer.pl -f call), so I don't 
think this new more explicit line is really necessary?


Thanks
Heiko


> Signed-off-by: Geert Uytterhoeven <geert at linux-m68k.org>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Cc: linux-arm-kernel at lists.infradead.org
> Cc: linux-rockchip at lists.infradead.org
> ---
> Please apply this patch directly if you want to be involved in device
> tree binding documentation for your subsystem.
> ---
>  MAINTAINERS | 1 +
>  1 file changed, 1 insertion(+)
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ea4e25a2f188aca1..e6b84eba4d574d13 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -1577,6 +1577,7 @@ L:	linux-arm-kernel at lists.infradead.org (moderated
> for non-subscribers) L:	linux-rockchip at lists.infradead.org
>  T:	git
> git://git.kernel.org/pub/scm/linux/kernel/git/mmind/linux-rockchip.git
> S:	Maintained
> +F:	Documentation/devicetree/bindings/soc/rockchip/
>  F:	arch/arm/boot/dts/rk3*
>  F:	arch/arm/mach-rockchip/
>  F:	drivers/clk/rockchip/



From LinoSanfilippo at gmx.de  Sun May 22 04:30:27 2016
From: LinoSanfilippo at gmx.de (Lino Sanfilippo)
Date: Sun, 22 May 2016 13:30:27 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160522091742.GA8681@debian-dorm>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com> <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com> <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm> <5740E82F.8040903@gmx.de>
 <20160522091742.GA8681@debian-dorm>
Message-ID: <57419853.9050701@gmx.de>

On 22.05.2016 11:17, Shuyu Wei wrote:

> Hi Lino,
> 
> I tested this patch, it still got panic under stress.
> Just wget 2 large files simultaneously and it failed.
> 
> Looks like the problem comes from the if statement in tx_clean().
> I changed your patch to use 
> 
> -               if (info & FOR_EMAC)
> +               if ((info & FOR_EMAC) || !txbd->data || !skb)
> 
> and it worked. 

Thanks for testing. However that extra check for skb not being NULL should not be
necessary if the code were correct. The changes I suggested were all about having
skb and info consistent with txbd_curr.
But I just realized that there is still a big flaw in the last changes. While
tx() looks correct now (we first set up the descriptor and assign the skb and _then_
advance txbd_curr) tx_clean still is not:

We _first_ have to read tx_curr and _then_ read the corresponding descriptor and its skb.
(The last patch implemented just the reverse - and thus wrong - order, first get skb and 
descriptor and then read tx_curr).

So the patch below hopefully handles also tx_clean correctly. Could you please do once more a test
with this one?


> 
> After further test, my patch to barrier timestamp() didn't work.
> Just like the original code in the tree, the emac still got stuck under
> high load, even if I changed the smp_wmb() to dma_wmb(). So the original
> code do have race somewhere.

So to make this clear: with the current code in net-next you still see a problem (lockup), right?

> 
> I'm new to kernel development, and still trying to understand how memory
> barrier works

Its an interresting topic and thats what I am trying to understand, too :)


> ... and why Francois' fix worked. Please be patient with me :-).

So which fix(es) exactly work for you and solve your lockup issue?


--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -159,12 +159,22 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 		unsigned int *txbd_dirty = &priv->txbd_dirty;
 		struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
 		struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
-		struct sk_buff *skb = tx_buff->skb;
 		unsigned int info = le32_to_cpu(txbd->info);
+		struct sk_buff *skb;
 
-		if ((info & FOR_EMAC) || !txbd->data || !skb)
+		if (*txbd_dirty == priv->txbd_curr)
 			break;
 
+		/* Make sure curr pointer is consistent with info */
+		rmb();
+
+		info = le32_to_cpu(txbd->info);
+
+		if (info & FOR_EMAC)
+			break;
+
+		skb = tx_buff->skb;
+
 		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
 			stats->tx_errors++;
 			stats->tx_dropped++;
@@ -195,8 +205,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 		*txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;
 	}
 
-	/* Ensure that txbd_dirty is visible to tx() before checking
-	 * for queue stopped.
+	/* Ensure that txbd_dirty is visible to tx() and we see the most recent
+	 * value for txbd_curr.
 	 */
 	smp_mb();
 
@@ -680,35 +690,29 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
 	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
 
 	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
-
-	/* Make sure pointer to data buffer is set */
-	wmb();
+	priv->tx_buff[*txbd_curr].skb = skb;
 
 	skb_tx_timestamp(skb);
 
 	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
-	/* Make sure info word is set */
+	/* 1. Make sure that with respect to tx_clean everything is set up
+	 * properly before we advance txbd_curr.
+	 * 2. Make sure writes to DMA descriptors are completed before we inform
+	 * the hardware.
+	 */
 	wmb();
 
-	priv->tx_buff[*txbd_curr].skb = skb;
-
 	/* Increment index to point to the next BD */
 	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
 
-	/* Ensure that tx_clean() sees the new txbd_curr before
-	 * checking the queue status. This prevents an unneeded wake
-	 * of the queue in tx_clean().
+	/* Ensure we see the most recent value of txbd_dirty and tx_clean() sees
+	 * the updated value of txbd_curr.
 	 */
 	smp_mb();
 
-	if (!arc_emac_tx_avail(priv)) {
+	if (!arc_emac_tx_avail(priv))
 		netif_stop_queue(ndev);
-		/* Refresh tx_dirty */
-		smp_mb();
-		if (arc_emac_tx_avail(priv))
-			netif_start_queue(ndev);
-	}
 
 	arc_reg_set(priv, R_STATUS, TXPL_MASK);
 
-- 
1.9.1





From romieu at fr.zoreil.com  Sun May 22 14:21:23 2016
From: romieu at fr.zoreil.com (Francois Romieu)
Date: Sun, 22 May 2016 23:21:23 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <5740E98A.5050803@gmx.de>
References: <20160517152520.GA2750@debian-dorm>
 <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com>
 <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com>
 <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm>
 <20160521194733.GA30557@electric-eye.fr.zoreil.com>
 <5740E98A.5050803@gmx.de>
Message-ID: <20160522212123.GA5086@electric-eye.fr.zoreil.com>

Lino Sanfilippo <LinoSanfilippo at gmx.de> :
> On 21.05.2016 21:47, Francois Romieu wrote:
> > Shuyu Wei <wsy2220 at gmail.com> :
> > [...]
> >> diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
> >> index a3a9392..c2447b0 100644
> >> --- a/drivers/net/ethernet/arc/emac_main.c
> >> +++ b/drivers/net/ethernet/arc/emac_main.c
> >> @@ -686,6 +686,9 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
> >>  
> >>         skb_tx_timestamp(skb);
> >>  
> >> +       /* Make sure timestamp is set */
> >> +       smp_wmb();
> > 
> > Should be dma_wmb() (see davem's message).
> > 
> > It's completely unrelated to SMP.
> > 
> 
> Its also completely unrelated to dma so I doubt that this is what davem meant.

It's related to dma: nobody wants the device to perform dma from memory
while the CPU is writing timestamp.

The device must enforce a commit of any network buffer memory write before
releasing control, i.e. before writing *info.

See 'git log -p --grep=dma_[rw]mb': it appears several times.

> As far as I understood he was referring to the dma descriptor.

If the wmb() between *info = ... and *txbd_curr = ... is replaced by a
dma_wmb(), the device will see a consistent descriptor when if performs
a DMA read after the CPU wrote into the mailbox (arc_reg_set(..., TXPL_MASK)).

Ok, I agree on this one.

However, it doesn't help with the (SMP) requirement that no CPU sees
the txbd_curr write before *info is written by the local CPU. Afaiui
dma_wmb() is too weak for this part. If we don't want wmb() here,
it will have to be dma_wmb() + smp_wmb().

-- 
Ueimor


From romieu at fr.zoreil.com  Sun May 22 15:36:59 2016
From: romieu at fr.zoreil.com (Francois Romieu)
Date: Mon, 23 May 2016 00:36:59 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <57419853.9050701@gmx.de>
References: <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com>
 <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com>
 <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm> <5740E82F.8040903@gmx.de>
 <20160522091742.GA8681@debian-dorm> <57419853.9050701@gmx.de>
Message-ID: <20160522223659.GB5086@electric-eye.fr.zoreil.com>

Lino Sanfilippo <LinoSanfilippo at gmx.de> :
[...]
> --- a/drivers/net/ethernet/arc/emac_main.c
> +++ b/drivers/net/ethernet/arc/emac_main.c
> @@ -159,12 +159,22 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>  		unsigned int *txbd_dirty = &priv->txbd_dirty;
>  		struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
>  		struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
> -		struct sk_buff *skb = tx_buff->skb;
>  		unsigned int info = le32_to_cpu(txbd->info);
> +		struct sk_buff *skb;
>  

Insert a smp_rmb() here to close one window for an outdated txbd_dirty value
(the "arc_emac_tx_clean wrote txbd_curr and issued smp_wmb" one).

Actually, insert smp_rmb() at the start of arc_emac_tx_clean() as it
does not need to be performed withing the loop and would penalize it.

Given the implicit smp barriers in the non-driver code, I consider
"arc_emac_tx_clean on one CPU does not read latest txbd_dirty value written
by previous arc_emac_tx_clean on different CPU" as utter onanism but
issueing smp_rmb() at the start of arc_emac_tx_clean() nails it as well.

> -		if ((info & FOR_EMAC) || !txbd->data || !skb)
> +		if (*txbd_dirty == priv->txbd_curr)
>  			break;

Ok, it's just the "while (priv->txbd_dirty != priv->txbd_curr) {" loop
in disguise.

>  
> +		/* Make sure curr pointer is consistent with info */
> +		rmb();
> +
> +		info = le32_to_cpu(txbd->info);
> +
> +		if (info & FOR_EMAC)
> +			break;

With proper ordering + barrier in arc_emac_tx() you can relax it to smp_rmb().

> +
> +		skb = tx_buff->skb;
> +
>  		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
>  			stats->tx_errors++;
>  			stats->tx_dropped++;
> @@ -195,8 +205,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>  		*txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;
>  	}
>  
> -	/* Ensure that txbd_dirty is visible to tx() before checking
> -	 * for queue stopped.
> +	/* Ensure that txbd_dirty is visible to tx() and we see the most recent
> +	 * value for txbd_curr.
>  	 */
>  	smp_mb();
>  
> @@ -680,35 +690,29 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
>  	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
>  
>  	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
> -
> -	/* Make sure pointer to data buffer is set */
> -	wmb();
> +	priv->tx_buff[*txbd_curr].skb = skb;
>  
>  	skb_tx_timestamp(skb);
>  
>  	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);

No.

You need dma_wmb() after skb_tx_timestamp() to commit skb_tx_timestamp() [*]
and data = cpu_to_le32(addr).

[*] I doubt anyone want a dma_sync_single_...() here.

>  
> -	/* Make sure info word is set */
> +	/* 1. Make sure that with respect to tx_clean everything is set up
> +	 * properly before we advance txbd_curr.
> +	 * 2. Make sure writes to DMA descriptors are completed before we inform
> +	 * the hardware.
> +	 */
>  	wmb();

Yes, either wmb() or smp_wmb() + dma_wmb().

>  
> -	priv->tx_buff[*txbd_curr].skb = skb;
> -
>  	/* Increment index to point to the next BD */
>  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
>  
> -	/* Ensure that tx_clean() sees the new txbd_curr before
> -	 * checking the queue status. This prevents an unneeded wake
> -	 * of the queue in tx_clean().
> +	/* Ensure we see the most recent value of txbd_dirty and tx_clean() sees
> +	 * the updated value of txbd_curr.
>  	 */
>  	smp_mb();

Nit: s/the most/a/

"a" as in "arc_emac_tx_clean() _is_ racing with arc_emac_tx"

>  
> -	if (!arc_emac_tx_avail(priv)) {
> +	if (!arc_emac_tx_avail(priv))
>  		netif_stop_queue(ndev);
> -		/* Refresh tx_dirty */
> -		smp_mb();
> -		if (arc_emac_tx_avail(priv))
> -			netif_start_queue(ndev);
> -	}

No.

I may sound like an old record but the revalidation part must be kept.

txbd_dirty may change in the arc_emac_tx_avail.. netif_stop_queue window
(the race requires a different CPU as arc_emac_tx() runs in locally
disabled BH context).

-- 
Ueimor


From shawn.lin at rock-chips.com  Sun May 22 17:48:19 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Mon, 23 May 2016 08:48:19 +0800
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <3647622.McCjKUuZmz@phil>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
 <3647622.McCjKUuZmz@phil>
Message-ID: <d0d2648a-a2d7-b57c-a434-490aab8d7958@rock-chips.com>

On 2016/5/21 5:13, Heiko Stuebner wrote:
> Hi Shawn,
>
> I haven't had any contact with PCI yet, so my comments below will likely
> address more generic findings only.
>
> As you might've guessed from the binding comments, to me it looks like the
> phy handling should be in a separate phy driver and looking below all phy
> accesses seem very separate from the actual pci controller interactions -
> they are even in port_init only as well.
>

yes, the main reason for not to seperate a new pcie-phy driver for this
prototype design is that I just wonder whether it's worth to create a
new driver for just a small piece of code. And a bit more forward is
that I think phy api is no so scalable for just init/power_on in
case of too much interactions between controller and phy from which I
suffer a bit for emmc.

Should I really need to seperate the phy part into pcie-phy? ;)

> While I already added some comments about that below, the driver seems full
> of raw register bit handling (including wild shifts). Please abstract that
> using contants, so that stuff stays readable for the future.

okay, let me migrate these magic number and raw reg bit handling into a
new header file.

>
>
> Am Freitag, 20. Mai 2016, 18:29:16 schrieb Shawn Lin:
>> RK3399 has a PCIe controller which can be used as Root Complex.
>> This driver supports a PCIe controller as Root Complex mode.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> ---
>
> [...]
>
>> diff --git a/drivers/pci/host/pcie-rockchip.c
>> b/drivers/pci/host/pcie-rockchip.c new file mode 100644
>> index 0000000..4063fd3
>> --- /dev/null
>> +++ b/drivers/pci/host/pcie-rockchip.c
>> @@ -0,0 +1,1181 @@
>> +/*
>> + * Rockchip AXI PCIe host controller driver
>> + *
>> + * Copyright (c) 2016 Rockchip, Inc.
>> + *
>> + * Author: Shawn Lin <shawn.lin at rock-chips.com>
>> + *         Wenrui Li <wenrui.li at rock-chips.com>
>> + * Bits taken from Synopsys Designware Host controller driver and
>> + * ARM PCI Host generic driver.
>> + *
>> + * This program is free software: you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation, either version 2 of the License, or
>> + * (at your option) any later version.
>> + */
>> +#include <linux/clk.h>
>> +#include <linux/delay.h>
>> +#include <linux/gpio/consumer.h>
>> +#include <linux/interrupt.h>
>> +#include <linux/irq.h>
>> +#include <linux/irqdomain.h>
>> +#include <linux/kernel.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/module.h>
>> +#include <linux/msi.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_device.h>
>> +#include <linux/of_pci.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/of_irq.h>
>> +#include <linux/pci.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/reset.h>
>> +#include <linux/regmap.h>
>> +
>> +#define REF_CLK_100MHZ			(100 * 1000 * 1000)
>
> seems unused

will be removed.

>
>> +#define PCIE_CLIENT_BASE		0x0
>> +#define PCIE_RC_CONFIG_BASE		0xa00000
>> +#define PCIE_CORE_CTRL_MGMT_BASE	0x900000
>> +#define PCIE_CORE_AXI_CONF_BASE		0xc00000
>> +#define PCIE_CORE_AXI_INBOUND_BASE	0xc00800
>> +
>> +#define PCIE_CLIENT_BASIC_STATUS0	0x44
>> +#define PCIE_CLIENT_BASIC_STATUS1	0x48
>> +#define PCIE_CLIENT_INT_MASK		0x4c
>> +#define PCIE_CLIENT_INT_STATUS		0x50
>> +#define PCIE_CORE_INT_MASK		0x900210
>> +#define PCIE_CORE_INT_STATUS		0x90020c
>> +
>> +/** Size of one AXI Region (not Region 0) */
>> +#define	AXI_REGION_SIZE			(0x1 << 20)
>
> for those generic (1 << x) things please use BIT(x) instead
> Also constants intertwined with constants is hard to read,
> so ideally add a blank line above each comment and comment style for single
> line comments only has one * in the beginning

Ahh yep.

> 	/* foo */
>
>> +/** Overall size of AXI area */
>> +#define	AXI_OVERALL_SIZE		(64 * (0x1 << 20))
>> +/** Size of Region 0, equal to sum of sizes of other regions */
>> +#define	AXI_REGION_0_SIZE		(32 * (0x1 << 20))
>> +#define OB_REG_SIZE_SHIFT		5
>> +#define IB_ROOT_PORT_REG_SIZE_SHIFT	3
>> +
>> +#define AXI_WRAPPER_IO_WRITE		0x6
>> +#define AXI_WRAPPER_MEM_WRITE		0x2
>> +#define MAX_AXI_IB_ROOTPORT_REGION_NUM	3
>> +#define	MIN_AXI_ADDR_BITS_PASSED	8
>
> strange spacing after #define

Generally I use one space after #define, but I donnot somehow...
I will check it twice.

>
> [...]
>
>> +/**
>> + * rockchip_pcie_init_port - Initialize hardware
>> + * @port: PCIe port information
>> + */
>> +static int rockchip_pcie_init_port(struct rockchip_pcie_port *port)
>> +{
>> +	int err;
>> +	u32 status;
>> +	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
>
> this timeout only seems to be initialized once here but used for multiple
> loops below resulting in all waitloops combined together being allowed to
> take 1 second ... is this intended?

a big timeout value to make sure we leave enough margin. No any data
is provided about how long should we wait for pll lock/re-lock/tainning
finish stuff. As it also related to the Socs/devices. Currently I
test pci-ethernet/wifi/SATA-bridge/USB-bridge, and it seems can be
reduced. But as you know, I cannot guarantee not to augment it once we
find some SSD/GPU in the failure state of trainning in the future.
Anyway I think here we use loop-break method, so it should be not
harmful?

>
>> +	gpiod_set_value(port->ep_gpio, 0);
>> +
>> +	/* Make sure PCIe relate block is in reset state */
>> +	err = reset_control_assert(port->phy_rst);
>> +	if (err) {
>> +		dev_err(port->dev, "assert phy_rst err %d\n", err);
>> +		return err;
>> +	}
>
> should move to phy driver probe or so
>
>> +	err = reset_control_assert(port->core_rst);
>> +	if (err) {
>> +		dev_err(port->dev, "assert core_rst err %d\n", err);
>> +		return err;
>> +	}
>
> blank line
>
>> +	err = reset_control_assert(port->mgmt_rst);
>> +	if (err) {
>> +		dev_err(port->dev, "assert mgmt_rst err %d\n", err);
>> +		return err;
>> +	}
>
> blank line
>
>> +	err = reset_control_assert(port->mgmt_sticky_rst);
>> +	if (err) {
>> +		dev_err(port->dev, "assert mgmt_sticky_rst err %d\n", err);
>> +		return err;
>> +	}
>
> blank line
>
>> +	err = reset_control_assert(port->pipe_rst);
>> +	if (err) {
>> +		dev_err(port->dev, "assert pipe_rst err %d\n", err);
>> +		return err;
>> +	}
>> +
>> +	pcie_write(port, (0xf << 20) | (0x1 << 16) | PCIE_CLIENT_GEN_SEL_2 |
>> +			  (0x1 << 19) | (0x1 << 3) |
>> +			  PCIE_CLIENT_MODE_RC |
>> +			  PCIE_CLIENT_CONF_LANE_NUM(port->lanes) |
>> +			  PCIE_CLIENT_CONF_ENABLE, PCIE_CLIENT_BASE);
>> +
>
> ------ phy_enable begin ------
>
> As mentioned above, the whole phy handling seems pretty separate, so should
> be easily being able to live in a real phy driver?
>
> This of course also needs to handle the phy clock in it.
>
>> +	err = reset_control_deassert(port->phy_rst);
>> +	if (err) {
>> +		dev_err(port->dev, "deassert phy_rst err %d\n", err);
>> +		return err;
>> +	}
>> +	regmap_write(port->grf, port->pcie_conf,
>> +		     (0x3f << 17) | (0x10 << 1));
>
> the bits above should use some sort of constant / description. Also see
> HIWORD_UPDATE in other drivers for the write-enable mask
>
> also add blank line here
>
>> +	err = -EINVAL;
>> +	while (time_before(jiffies, timeout)) {
>> +		regmap_read(port->grf, port->pcie_status, &status);
>> +		if ((status & (1 << 9))) {
>
> use a constant for the (1 << 9) [aka BIT(9)] please
>
>> +			dev_info(port->dev, "pll locked!\n");
>
> dev_dbg instead?

yep

>
>> +			err = 0;
>> +			break;
>> +		}
>> +	}
>> +	if (err) {
>> +		dev_err(port->dev, "pll lock timeout!\n");
>> +		return err;
>> +	}
>> +	pcie_pb_wr_cfg(port, 0x10, 0x8);
>> +	pcie_pb_wr_cfg(port, 0x12, 0x8);
>> +
>> +	err = -ETIMEDOUT;
>> +	while (time_before(jiffies, timeout)) {
>> +		regmap_read(port->grf, port->pcie_status, &status);
>> +		if (!(status & (1 << 10))) {
>
> constant again
>
>> +			dev_info(port->dev, "pll output enable done!\n");
>
> dev_dbg or leave it out

dev_dbg should be fine.

>
>> +			err = 0;
>> +			break;
>> +		}
>> +	}
>> +
>> +	if (err) {
>> +		dev_err(port->dev, "pll output enable timeout!\n");
>> +		return err;
>> +	}
>> +
>> +	regmap_write(port->grf, port->pcie_conf,
>> +		     (0x3f << 17) | (0x10 << 1));
>> +	err = -EINVAL;
>> +	while (time_before(jiffies, timeout)) {
>> +		regmap_read(port->grf, port->pcie_status, &status);
>> +		if ((status & (1 << 9))) {
>> +			dev_info(port->dev, "pll relocked!\n");
>> +			err = 0;
>> +			break;
>> +		}
>> +	}
>> +	if (err) {
>> +		dev_err(port->dev, "pll relock timeout!\n");
>> +		return err;
>> +	}
>
> ------ phy_enable end ------
>
>
>> +	err = reset_control_deassert(port->core_rst);
>> +	if (err) {
>> +		dev_err(port->dev, "deassert core_rst err %d\n", err);
>> +		return err;
>> +	}
>> +	err = reset_control_deassert(port->mgmt_rst);
>> +	if (err) {
>> +		dev_err(port->dev, "deassert mgmt_rst err %d\n", err);
>> +		return err;
>> +	}
>> +	err = reset_control_deassert(port->mgmt_sticky_rst);
>> +	if (err) {
>> +		dev_err(port->dev, "deassert mgmt_sticky_rst err %d\n", err);
>> +		return err;
>> +	}
>> +	err = reset_control_deassert(port->pipe_rst);
>> +	if (err) {
>> +		dev_err(port->dev, "deassert pipe_rst err %d\n", err);
>> +		return err;
>> +	}
>> +
>> +	pcie_write(port, 1 << 17 | 1 << 1, PCIE_CLIENT_BASE);
>> +
>> +	gpiod_set_value(port->ep_gpio, 1);
>> +	err = -ETIMEDOUT;
>> +	while (time_before(jiffies, timeout)) {
>> +		status = pcie_read(port, PCIE_CLIENT_BASIC_STATUS1);
>> +		if (((status >> 20) & 0x3) == 0x3) {
>> +			dev_info(port->dev, "pcie link training gen1 pass!\n");
>> +			err = 0;
>> +			break;
>> +		}
>> +	}
>> +	if (err) {
>> +		dev_err(port->dev, "pcie link training gen1 timeout!\n");
>> +		return err;
>> +	}
>> +
>> +	status = pcie_read(port, 0x9000d0);
>> +	status |= 0x20;
>> +	pcie_write(port, status, 0x9000d0);
>
> just to mention it again, bit handling as descriptive constant please and
> also please give that register a name :-)

will address this magic number all above using a new header file :)

>
> [...]
>
>> +static int rockchip_pcie_parse_dt(struct rockchip_pcie_port *port)
>> +{
>
> [...]
>
>> +	port->lanes = 1;
>> +	err = of_property_read_u32(node, "num-lanes", &port->lanes);
>> +	if (!err && ((port->lanes == 0) ||
>> +		     (port->lanes == 3) ||
>> +		     (port->lanes > 4))) {
>> +		dev_info(dev, "invalid num-lanes, default use one lane\n");
>
> dev_warn might be more appropriate

sure.

>
>> +		port->lanes = 1;
>> +	}
>
> [...]
>
>> +static void rockchip_pcie_msi_enable(struct rockchip_pcie_port *pp)
>> +{
>> +	struct device_node *msi_node;
>> +
>> +	msi_node = of_parse_phandle(pp->dev->of_node,
>> +				    "msi-parent", 0);
>
> I would assume this should live in the general parse_dt function?
> Also is that MSI enablement really allow to fail silently without any affect
> on the PCI functionality?

yes, we should check this as well as CONFIG_PCI_MSI.
Will fix it.


>
>> +	if (!msi_node)
>> +		return;
>> +
>> +	pp->msi = of_pci_find_msi_chip_by_node(msi_node);
>> +	of_node_put(msi_node);
>> +
>> +	if (pp->msi)
>> +		pp->msi->dev = pp->dev;
>> +}
>
> [...]
>
>> +static int rockchip_pcie_probe(struct platform_device *pdev)
>> +{
>> +	struct rockchip_pcie_port *port;
>> +	struct device *dev = &pdev->dev;
>> +	struct pci_bus *bus, *child;
>> +	struct resource_entry *win;
>> +	int reg_no;
>> +	int err = 0;
>> +	int irq;
>> +	LIST_HEAD(res);
>> +
>> +	if (!dev->of_node)
>> +		return -ENODEV;
>> +
>> +	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
>> +	if (!port)
>> +		return -ENOMEM;
>> +
>> +	irq = platform_get_irq_byname(pdev, "pcie-sys");
>> +	if (irq < 0) {
>> +		dev_err(dev, "missing pcie_sys IRQ resource\n");
>> +		return -EINVAL;
>> +	}
>
> blank line
>
>> +	err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler,
>> +			       IRQF_SHARED, "pcie-sys", port);
>> +	if (err) {
>> +		dev_err(dev, "failed to request pcie subsystem irq\n");
>> +		return err;
>> +	}
>> +
>> +	port->irq = platform_get_irq_byname(pdev, "pcie-legacy");
>> +	if (port->irq < 0) {
>> +		dev_err(dev, "missing pcie_legacy IRQ resource\n");
>> +		return -EINVAL;
>> +	}
>
> blank line
>
>> +	err = devm_request_irq(dev, port->irq,
>> +			       rockchip_pcie_legacy_int_handler,
>> +			       IRQF_SHARED,
>> +			       "pcie-legacy",
>> +			       port);
>> +	if (err) {
>> +		dev_err(&pdev->dev, "failed to request pcie-legacy irq\n");
>> +		return err;
>> +	}
>> +
>> +	irq = platform_get_irq_byname(pdev, "pcie-client");
>> +	if (irq < 0) {
>> +		dev_err(dev, "missing pcie-client IRQ resource\n");
>> +		return -EINVAL;
>> +	}
>
> blank line
>
>> +	err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler,
>> +			       IRQF_SHARED, "pcie-client", port);
>> +	if (err) {
>> +		dev_err(dev, "failed to request pcie client irq\n");
>> +		return err;
>> +	}
>> +
>> +	port->dev = dev;
>> +	err = rockchip_pcie_parse_dt(port);
>> +	if (err) {
>> +		dev_err(dev, "Parsing DT failed\n");
>> +		return err;
>> +	}
>
> rockchip_pcie_parse_dt already emits error messages that are a lot more
> specific to the actual problem, so you don't need another error message here
> and can just return the error code.
>

okay.

>
>> +	err = rockchip_pcie_init_port(port);
>> +	if (err)
>> +		return err;
>> +
>> +	platform_set_drvdata(pdev, port);
>> +
>> +	rockchip_pcie_enable_interrupts(port);
>> +	if (!IS_ENABLED(CONFIG_PCI_MSI)) {
>> +		err = rockchip_pcie_init_irq_domain(port);
>> +		if (err < 0)
>> +			return err;
>> +	}
>> +
>> +	err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff,
>> +					       &res, &port->io_base);
>> +	if (err)
>> +		return err;
>
> add blank line
>
>
> Heiko
>
>
>


-- 
Best Regards
Shawn Lin



From zhengsq at rock-chips.com  Sun May 22 18:37:14 2016
From: zhengsq at rock-chips.com (Shunqian Zheng)
Date: Mon, 23 May 2016 09:37:14 +0800
Subject: [PATCH 0/5] iommu/rockchip: fix bugs; enable iommu for ARM64
Message-ID: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>

Fix a few bugs for rockchip iommu and enable for ARM64.

Simon (5):
  iommu/rockchip: fix devm_request_irq and devm_free_irq parameter
  iommu/rockchip: add map_sg callback for rk_iommu_ops
  iommu/rockchip: add sanity check for virtual device
  iommu/rockchip: add ARM64 cache flush operation for iommu
  iommu/rockchip: enable rockchip iommu on ARM64 platform

 drivers/iommu/Kconfig          |  2 +-
 drivers/iommu/rockchip-iommu.c | 16 +++++++++++++---
 2 files changed, 14 insertions(+), 4 deletions(-)

-- 
1.9.1



From zhengsq at rock-chips.com  Sun May 22 18:37:16 2016
From: zhengsq at rock-chips.com (Shunqian Zheng)
Date: Mon, 23 May 2016 09:37:16 +0800
Subject: [PATCH 2/5] iommu/rockchip: add map_sg callback for rk_iommu_ops
In-Reply-To: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
References: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
Message-ID: <1463967439-13354-3-git-send-email-zhengsq@rock-chips.com>

From: Simon <xxm at rock-chips.com>

The iommu_dma_alloc() in iommu/dma-iommu.c calls iommu_map_sg()
that requires the callback iommu_ops .map_sg(). Adding the
default_iommu_map_sg() to rockchip iommu accordingly.

Signed-off-by: Simon <xxm at rock-chips.com>
---
 drivers/iommu/rockchip-iommu.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index ec0ce62..3c16ec3 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -1022,6 +1022,7 @@ static const struct iommu_ops rk_iommu_ops = {
 	.detach_dev = rk_iommu_detach_device,
 	.map = rk_iommu_map,
 	.unmap = rk_iommu_unmap,
+	.map_sg = default_iommu_map_sg,
 	.add_device = rk_iommu_add_device,
 	.remove_device = rk_iommu_remove_device,
 	.iova_to_phys = rk_iommu_iova_to_phys,
-- 
1.9.1



From zhengsq at rock-chips.com  Sun May 22 18:37:15 2016
From: zhengsq at rock-chips.com (Shunqian Zheng)
Date: Mon, 23 May 2016 09:37:15 +0800
Subject: [PATCH 1/5] iommu/rockchip: fix devm_request_irq and devm_free_irq
 parameter
In-Reply-To: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
References: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
Message-ID: <1463967439-13354-2-git-send-email-zhengsq@rock-chips.com>

From: Simon <xxm at rock-chips.com>

When rk_iommu_attach_device or rk_iommu_detach_device be called, the second
parameter "dev" represent the device who own the iommu, so it is not resonable
using "dev" for devm_request_irq's first parameter. To avoid potential error,
we must use iommu device itself "iommu->dev" instead, the same as devm_free_irq.

Signed-off-by: Simon <xxm at rock-chips.com>
---
 drivers/iommu/rockchip-iommu.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index c7d6156..ec0ce62 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -807,7 +807,7 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
 
 	iommu->domain = domain;
 
-	ret = devm_request_irq(dev, iommu->irq, rk_iommu_irq,
+	ret = devm_request_irq(iommu->dev, iommu->irq, rk_iommu_irq,
 			       IRQF_SHARED, dev_name(dev), iommu);
 	if (ret)
 		return ret;
@@ -860,7 +860,7 @@ static void rk_iommu_detach_device(struct iommu_domain *domain,
 	}
 	rk_iommu_disable_stall(iommu);
 
-	devm_free_irq(dev, iommu->irq, iommu);
+	devm_free_irq(iommu->dev, iommu->irq, iommu);
 
 	iommu->domain = NULL;
 
-- 
1.9.1



From zhengsq at rock-chips.com  Sun May 22 18:37:18 2016
From: zhengsq at rock-chips.com (Shunqian Zheng)
Date: Mon, 23 May 2016 09:37:18 +0800
Subject: [PATCH 4/5] iommu/rockchip: add ARM64 cache flush operation for iommu
In-Reply-To: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
References: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
Message-ID: <1463967439-13354-5-git-send-email-zhengsq@rock-chips.com>

From: Simon <xxm at rock-chips.com>

Signed-off-by: Simon <xxm at rock-chips.com>
---
 drivers/iommu/rockchip-iommu.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 043d18c..1741b65 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -95,12 +95,16 @@ struct rk_iommu {
 
 static inline void rk_table_flush(u32 *va, unsigned int count)
 {
+#if defined(CONFIG_ARM)
 	phys_addr_t pa_start = virt_to_phys(va);
 	phys_addr_t pa_end = virt_to_phys(va + count);
 	size_t size = pa_end - pa_start;
 
 	__cpuc_flush_dcache_area(va, size);
 	outer_flush_range(pa_start, pa_end);
+#elif defined(CONFIG_ARM64)
+	__dma_flush_range(va, va + count);
+#endif
 }
 
 static struct rk_iommu_domain *to_rk_domain(struct iommu_domain *dom)
-- 
1.9.1



From zhengsq at rock-chips.com  Sun May 22 18:37:17 2016
From: zhengsq at rock-chips.com (Shunqian Zheng)
Date: Mon, 23 May 2016 09:37:17 +0800
Subject: [PATCH 3/5] iommu/rockchip: add sanity check for virtual device
In-Reply-To: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
References: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
Message-ID: <1463967439-13354-4-git-send-email-zhengsq@rock-chips.com>

From: Simon <xxm at rock-chips.com>

We mark DRM as "virtual" device by checking it's group,
which may no longer true with the new rockchip drm drv in
https://patchwork.kernel.org/patch/8876331/.

Checking the group->iommu_data for virtual device.

Signed-off-by: Simon <xxm at rock-chips.com>
---
 drivers/iommu/rockchip-iommu.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
index 3c16ec3..043d18c 100644
--- a/drivers/iommu/rockchip-iommu.c
+++ b/drivers/iommu/rockchip-iommu.c
@@ -764,6 +764,7 @@ static size_t rk_iommu_unmap(struct iommu_domain *domain, unsigned long _iova,
 	return unmap_size;
 }
 
+/* Return NULL for a virtual device like DRM */
 static struct rk_iommu *rk_iommu_from_dev(struct device *dev)
 {
 	struct iommu_group *group;
@@ -774,6 +775,11 @@ static struct rk_iommu *rk_iommu_from_dev(struct device *dev)
 	if (!group)
 		return NULL;
 	iommu_dev = iommu_group_get_iommudata(group);
+	if (!iommu_dev) {
+		dev_info(dev, "Possibly a virtual device\n");
+		return NULL;
+	}
+
 	rk_iommu = dev_get_drvdata(iommu_dev);
 	iommu_group_put(group);
 
@@ -791,7 +797,6 @@ static int rk_iommu_attach_device(struct iommu_domain *domain,
 
 	/*
 	 * Allow 'virtual devices' (e.g., drm) to attach to domain.
-	 * Such a device does not belong to an iommu group.
 	 */
 	iommu = rk_iommu_from_dev(dev);
 	if (!iommu)
-- 
1.9.1



From zhengsq at rock-chips.com  Sun May 22 18:37:19 2016
From: zhengsq at rock-chips.com (Shunqian Zheng)
Date: Mon, 23 May 2016 09:37:19 +0800
Subject: [PATCH 5/5] iommu/rockchip: enable rockchip iommu on ARM64 platform
In-Reply-To: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
References: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
Message-ID: <1463967439-13354-6-git-send-email-zhengsq@rock-chips.com>

From: Simon <xxm at rock-chips.com>

Signed-off-by: Simon <xxm at rock-chips.com>
---
 drivers/iommu/Kconfig | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index ad08603..5572621 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -218,7 +218,7 @@ config OMAP_IOMMU_DEBUG
 
 config ROCKCHIP_IOMMU
 	bool "Rockchip IOMMU Support"
-	depends on ARM
+	depends on ARM || ARM64
 	depends on ARCH_ROCKCHIP || COMPILE_TEST
 	select IOMMU_API
 	select ARM_DMA_USE_IOMMU
-- 
1.9.1



From zhengxing at rock-chips.com  Sun May 22 20:11:48 2016
From: zhengxing at rock-chips.com (Xing Zheng)
Date: Mon, 23 May 2016 11:11:48 +0800
Subject: [PATCH] ASoC: rockchip: Add machine driver for MAX98357A/RT5514/DA7219
Message-ID: <1463973108-8699-1-git-send-email-zhengxing@rock-chips.com>

There are multi codec devices on the RK3399 platform, we can use
this patch support and control these codecs.

Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
---

 .../sound/rockchip-max98357a-rt5514-da7219.txt     |   15 +
 sound/soc/rockchip/Kconfig                         |   11 +
 sound/soc/rockchip/Makefile                        |    2 +
 .../rockchip/rockchip_max98357a_rt5514_da7219.c    |  339 ++++++++++++++++++++
 4 files changed, 367 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
 create mode 100644 sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c

diff --git a/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
new file mode 100644
index 0000000..5928384
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
@@ -0,0 +1,15 @@
+ROCKCHIP with MAX98357A/RT5514/DA7219 codecs
+
+Required properties:
+- compatible: "rockchip,rockchip-sound"
+- rockchip,cpu: The phandle of the Rockchip I2S controller that's
+  connected to the codecs
+- rockchip,codec: The phandle of the MAX98357A/RT5514/DA7219 codecs
+
+Example:
+
+sound {
+	compatible = "rockchip,rockchip-sound";
+	rockchip,cpu = <&i2s0 &i2s0 &i2s1>;
+	rockchip,codec = <&max98357a &headsetcodec &codec>;
+};
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index f1e0c70..d02aa94 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -41,3 +41,14 @@ config SND_SOC_ROCKCHIP_RT5645
 	help
 	  Say Y or M here if you want to add support for SoC audio on Rockchip
 	  boards using the RT5645/RT5650 codec, such as Veyron.
+
+config SND_SOC_ROCKCHIP_MAX98357A_RT5514_DA7219
+	tristate "ASoC support for Rockchip boards using the MAX98357A/RT5514/DA7219"
+	depends on SND_SOC_ROCKCHIP && GPIOLIB
+	select SND_SOC_ROCKCHIP_I2S
+	select SND_SOC_MAX98357A
+	select SND_SOC_RT5514
+	select SND_SOC_DA7219
+	help
+	  Say Y or M here if you want to add support for SoC audio on Rockchip
+	  boards using the MAX98357A/RT5514/DA7219.
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index c0bf560..ca97489 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
 
 snd-soc-rockchip-max98090-objs := rockchip_max98090.o
 snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
+snd-soc-rockchip-max98357a-rt5514-da7219-objs := rockchip_max98357a_rt5514_da7219.o
 
 obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
+obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98357A_RT5514_DA7219) += snd-soc-rockchip-max98357a-rt5514-da7219.o
diff --git a/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c b/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c
new file mode 100644
index 0000000..50c0d35
--- /dev/null
+++ b/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c
@@ -0,0 +1,339 @@
+/*
+ * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
+ *
+ * Copyright (c) 2016, ROCKCHIP CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "rockchip_i2s.h"
+#include "../codecs/da7219.h"
+#include "../codecs/da7219-aad.h"
+#include "../codecs/rt5514.h"
+
+#define DRV_NAME "rockchip-sound"
+
+static struct snd_soc_jack rockchip_sound_jack;
+
+static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphones", NULL),
+	SND_SOC_DAPM_SPK("Speakers", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route rockchip_dapm_routes[] = {
+	/* Input Lines */
+	{"MIC", NULL, "Headset Mic"},
+	{"DMIC1L", NULL, "Int Mic"},
+	{"DMIC1R", NULL, "Int Mic"},
+
+	/* Output Lines */
+	{"Headphones", NULL, "HPL"},
+	{"Headphones", NULL, "HPR"},
+	{"Speakers", NULL, "Speakers"},
+};
+
+static const struct snd_kcontrol_new rockchip_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphones"),
+	SOC_DAPM_PIN_SWITCH("Speakers"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Int Mic"),
+};
+
+static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+	unsigned int mclk;
+	int ret;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		mclk = 12288000;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
+	if (ret) {
+		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
+				__func__, mclk, ret);
+		return ret;
+	}
+
+	snd_soc_dapm_disable_pin(dapm, "Headphones");
+	snd_soc_dapm_enable_pin(dapm, "Speakers");
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	unsigned int mclk;
+	int ret;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 32000:
+	case 48000:
+	case 96000:
+		mclk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		mclk = 11289600;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+				     SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,
+				     mclk, SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
+				__func__, params_rate(params) * 512, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+	int mclk, ret;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 32000:
+	case 48000:
+	case 96000:
+		mclk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+		mclk = 11289600;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+				     SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);
+		return ret;
+	}
+
+	snd_soc_dapm_disable_pin(dapm, "Speakers");
+	snd_soc_dapm_enable_pin(dapm, "Headphones");
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec_dais[0]->codec;
+	int ret;
+
+	/* Enable Headset and 4 Buttons Jack detection */
+	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+				    SND_JACK_HEADSET |
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
+				    &rockchip_sound_jack, NULL, 0);
+
+	if (ret) {
+		dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);
+		return ret;
+	}
+
+	da7219_aad_jack_det(codec, &rockchip_sound_jack);
+
+	return 0;
+}
+
+static struct snd_soc_ops rockchip_sound_max98357a_ops = {
+	.hw_params = rockchip_sound_max98357a_hw_params,
+};
+
+static struct snd_soc_ops rockchip_sound_rt5514_ops = {
+	.hw_params = rockchip_sound_rt5514_hw_params,
+};
+
+static struct snd_soc_ops rockchip_sound_da7219_ops = {
+	.hw_params = rockchip_sound_da7219_hw_params,
+};
+
+enum {
+	DAILINK_MAX98357A,
+	DAILINK_RT5514,
+	DAILINK_DA7219,
+};
+
+static struct snd_soc_dai_link rockchip_dailinks[] = {
+	[DAILINK_MAX98357A] = {
+		.name = "MAX98357A",
+		.stream_name = "MAX98357A PCM",
+		.codec_dai_name = "HiFi",
+		.ops = &rockchip_sound_max98357a_ops,
+		/* set max98357a as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+	[DAILINK_RT5514] = {
+		.name = "RT5514",
+		.stream_name = "RT5514 PCM",
+		.codec_dai_name = "rt5514-aif1",
+		.ops = &rockchip_sound_rt5514_ops,
+		/* set rt5514 as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+	[DAILINK_DA7219] = {
+		.name = "DA7219",
+		.stream_name = "DA7219 PCM",
+		.codec_dai_name = "da7219-hifi",
+		.init = rockchip_sound_da7219_init,
+		.ops = &rockchip_sound_da7219_ops,
+		/* set da7219 as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+};
+
+static struct snd_soc_card rockchip_sound_card = {
+	.name = "rockchip-sound",
+	.owner = THIS_MODULE,
+	.dai_link = rockchip_dailinks,
+	.num_links =  ARRAY_SIZE(rockchip_dailinks),
+	.dapm_widgets = rockchip_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
+	.dapm_routes = rockchip_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
+	.controls = rockchip_controls,
+	.num_controls = ARRAY_SIZE(rockchip_controls),
+};
+
+static int rockchip_sound_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &rockchip_sound_card;
+	struct device_node *cpu_node;
+	int i, ret;
+
+	for (i = 0; i < card->num_links; i++) {
+		cpu_node = of_parse_phandle(pdev->dev.of_node,
+					 "rockchip,cpu", i);
+		if (!cpu_node) {
+			dev_err(&pdev->dev, "Property[%d] 'rockchip,cpu' missing or invalid\n", i);
+			return -EINVAL;
+		}
+
+		rockchip_dailinks[i].platform_of_node = cpu_node;
+		rockchip_dailinks[i].cpu_of_node = cpu_node;
+
+		rockchip_dailinks[i].codec_of_node =
+			of_parse_phandle(pdev->dev.of_node, "rockchip,codec", i);
+		if (!rockchip_dailinks[i].codec_of_node) {
+			dev_err(&pdev->dev,
+				"Property[%d] 'rockchip,codec' missing or invalid\n", i);
+			return -EINVAL;
+		}
+	}
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static const struct of_device_id rockchip_sound_of_match[] = {
+	{ .compatible = "rockchip,rockchip-sound", },
+	{},
+};
+
+static struct platform_driver rockchip_sound_driver = {
+	.probe = rockchip_sound_probe,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = rockchip_sound_of_match,
+#ifdef CONFIG_PM
+		.pm = &snd_soc_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(rockchip_sound_driver);
+
+MODULE_AUTHOR("Xing Zheng <zhengxing at rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);
-- 
1.7.9.5




From shawn.lin at rock-chips.com  Sun May 22 20:27:57 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Mon, 23 May 2016 11:27:57 +0800
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <d0d2648a-a2d7-b57c-a434-490aab8d7958@rock-chips.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
 <3647622.McCjKUuZmz@phil>
 <d0d2648a-a2d7-b57c-a434-490aab8d7958@rock-chips.com>
Message-ID: <ba4bc10c-a757-81ff-713d-5aa85012c64f@rock-chips.com>

On 2016/5/23 8:48, Shawn Lin wrote:
> On 2016/5/21 5:13, Heiko Stuebner wrote:
>> Hi Shawn,
>>
>> I haven't had any contact with PCI yet, so my comments below will likely
>> address more generic findings only.
>>
>> As you might've guessed from the binding comments, to me it looks like
>> the
>> phy handling should be in a separate phy driver and looking below all phy
>> accesses seem very separate from the actual pci controller interactions -
>> they are even in port_init only as well.
>>
>
> yes, the main reason for not to seperate a new pcie-phy driver for this
> prototype design is that I just wonder whether it's worth to create a
> new driver for just a small piece of code. And a bit more forward is
> that I think phy api is no so scalable for just init/power_on in
> case of too much interactions between controller and phy from which I
> suffer a bit for emmc.
>
> Should I really need to seperate the phy part into pcie-phy? ;)

Currently, We still need some more interactions between phy and 
controller here, not just what you point out in the comments. so if we
need a seperate phy driver, could it allows me to export some functions
for pcie driver?


>
>> While I already added some comments about that below, the driver seems
>> full
>> of raw register bit handling (including wild shifts). Please abstract
>> that
>> using contants, so that stuff stays readable for the future.
>
> okay, let me migrate these magic number and raw reg bit handling into a
> new header file.
>
>>
>>
>> Am Freitag, 20. Mai 2016, 18:29:16 schrieb Shawn Lin:
>>> RK3399 has a PCIe controller which can be used as Root Complex.
>>> This driver supports a PCIe controller as Root Complex mode.
>>>
>>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>> ---
>>
>> [...]
>>
>>> diff --git a/drivers/pci/host/pcie-rockchip.c
>>> b/drivers/pci/host/pcie-rockchip.c new file mode 100644
>>> index 0000000..4063fd3
>>> --- /dev/null
>>> +++ b/drivers/pci/host/pcie-rockchip.c
>>> @@ -0,0 +1,1181 @@
>>> +/*
>>> + * Rockchip AXI PCIe host controller driver
>>> + *
>>> + * Copyright (c) 2016 Rockchip, Inc.
>>> + *
>>> + * Author: Shawn Lin <shawn.lin at rock-chips.com>
>>> + *         Wenrui Li <wenrui.li at rock-chips.com>
>>> + * Bits taken from Synopsys Designware Host controller driver and
>>> + * ARM PCI Host generic driver.
>>> + *
>>> + * This program is free software: you can redistribute it and/or modify
>>> + * it under the terms of the GNU General Public License as published by
>>> + * the Free Software Foundation, either version 2 of the License, or
>>> + * (at your option) any later version.
>>> + */
>>> +#include <linux/clk.h>
>>> +#include <linux/delay.h>
>>> +#include <linux/gpio/consumer.h>
>>> +#include <linux/interrupt.h>
>>> +#include <linux/irq.h>
>>> +#include <linux/irqdomain.h>
>>> +#include <linux/kernel.h>
>>> +#include <linux/mfd/syscon.h>
>>> +#include <linux/module.h>
>>> +#include <linux/msi.h>
>>> +#include <linux/of_address.h>
>>> +#include <linux/of_device.h>
>>> +#include <linux/of_pci.h>
>>> +#include <linux/of_platform.h>
>>> +#include <linux/of_irq.h>
>>> +#include <linux/pci.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/reset.h>
>>> +#include <linux/regmap.h>
>>> +
>>> +#define REF_CLK_100MHZ            (100 * 1000 * 1000)
>>
>> seems unused
>
> will be removed.
>
>>
>>> +#define PCIE_CLIENT_BASE        0x0
>>> +#define PCIE_RC_CONFIG_BASE        0xa00000
>>> +#define PCIE_CORE_CTRL_MGMT_BASE    0x900000
>>> +#define PCIE_CORE_AXI_CONF_BASE        0xc00000
>>> +#define PCIE_CORE_AXI_INBOUND_BASE    0xc00800
>>> +
>>> +#define PCIE_CLIENT_BASIC_STATUS0    0x44
>>> +#define PCIE_CLIENT_BASIC_STATUS1    0x48
>>> +#define PCIE_CLIENT_INT_MASK        0x4c
>>> +#define PCIE_CLIENT_INT_STATUS        0x50
>>> +#define PCIE_CORE_INT_MASK        0x900210
>>> +#define PCIE_CORE_INT_STATUS        0x90020c
>>> +
>>> +/** Size of one AXI Region (not Region 0) */
>>> +#define    AXI_REGION_SIZE            (0x1 << 20)
>>
>> for those generic (1 << x) things please use BIT(x) instead
>> Also constants intertwined with constants is hard to read,
>> so ideally add a blank line above each comment and comment style for
>> single
>> line comments only has one * in the beginning
>
> Ahh yep.
>
>>     /* foo */
>>
>>> +/** Overall size of AXI area */
>>> +#define    AXI_OVERALL_SIZE        (64 * (0x1 << 20))
>>> +/** Size of Region 0, equal to sum of sizes of other regions */
>>> +#define    AXI_REGION_0_SIZE        (32 * (0x1 << 20))
>>> +#define OB_REG_SIZE_SHIFT        5
>>> +#define IB_ROOT_PORT_REG_SIZE_SHIFT    3
>>> +
>>> +#define AXI_WRAPPER_IO_WRITE        0x6
>>> +#define AXI_WRAPPER_MEM_WRITE        0x2
>>> +#define MAX_AXI_IB_ROOTPORT_REGION_NUM    3
>>> +#define    MIN_AXI_ADDR_BITS_PASSED    8
>>
>> strange spacing after #define
>
> Generally I use one space after #define, but I donnot somehow...
> I will check it twice.
>
>>
>> [...]
>>
>>> +/**
>>> + * rockchip_pcie_init_port - Initialize hardware
>>> + * @port: PCIe port information
>>> + */
>>> +static int rockchip_pcie_init_port(struct rockchip_pcie_port *port)
>>> +{
>>> +    int err;
>>> +    u32 status;
>>> +    unsigned long timeout = jiffies + msecs_to_jiffies(1000);
>>
>> this timeout only seems to be initialized once here but used for multiple
>> loops below resulting in all waitloops combined together being allowed to
>> take 1 second ... is this intended?
>
> a big timeout value to make sure we leave enough margin. No any data
> is provided about how long should we wait for pll lock/re-lock/tainning
> finish stuff. As it also related to the Socs/devices. Currently I
> test pci-ethernet/wifi/SATA-bridge/USB-bridge, and it seems can be
> reduced. But as you know, I cannot guarantee not to augment it once we
> find some SSD/GPU in the failure state of trainning in the future.
> Anyway I think here we use loop-break method, so it should be not
> harmful?
>
>>
>>> +    gpiod_set_value(port->ep_gpio, 0);
>>> +
>>> +    /* Make sure PCIe relate block is in reset state */
>>> +    err = reset_control_assert(port->phy_rst);
>>> +    if (err) {
>>> +        dev_err(port->dev, "assert phy_rst err %d\n", err);
>>> +        return err;
>>> +    }
>>
>> should move to phy driver probe or so
>>
>>> +    err = reset_control_assert(port->core_rst);
>>> +    if (err) {
>>> +        dev_err(port->dev, "assert core_rst err %d\n", err);
>>> +        return err;
>>> +    }
>>
>> blank line
>>
>>> +    err = reset_control_assert(port->mgmt_rst);
>>> +    if (err) {
>>> +        dev_err(port->dev, "assert mgmt_rst err %d\n", err);
>>> +        return err;
>>> +    }
>>
>> blank line
>>
>>> +    err = reset_control_assert(port->mgmt_sticky_rst);
>>> +    if (err) {
>>> +        dev_err(port->dev, "assert mgmt_sticky_rst err %d\n", err);
>>> +        return err;
>>> +    }
>>
>> blank line
>>
>>> +    err = reset_control_assert(port->pipe_rst);
>>> +    if (err) {
>>> +        dev_err(port->dev, "assert pipe_rst err %d\n", err);
>>> +        return err;
>>> +    }
>>> +
>>> +    pcie_write(port, (0xf << 20) | (0x1 << 16) |
>>> PCIE_CLIENT_GEN_SEL_2 |
>>> +              (0x1 << 19) | (0x1 << 3) |
>>> +              PCIE_CLIENT_MODE_RC |
>>> +              PCIE_CLIENT_CONF_LANE_NUM(port->lanes) |
>>> +              PCIE_CLIENT_CONF_ENABLE, PCIE_CLIENT_BASE);
>>> +
>>
>> ------ phy_enable begin ------
>>
>> As mentioned above, the whole phy handling seems pretty separate, so
>> should
>> be easily being able to live in a real phy driver?
>>
>> This of course also needs to handle the phy clock in it.
>>
>>> +    err = reset_control_deassert(port->phy_rst);
>>> +    if (err) {
>>> +        dev_err(port->dev, "deassert phy_rst err %d\n", err);
>>> +        return err;
>>> +    }
>>> +    regmap_write(port->grf, port->pcie_conf,
>>> +             (0x3f << 17) | (0x10 << 1));
>>
>> the bits above should use some sort of constant / description. Also see
>> HIWORD_UPDATE in other drivers for the write-enable mask
>>
>> also add blank line here
>>
>>> +    err = -EINVAL;
>>> +    while (time_before(jiffies, timeout)) {
>>> +        regmap_read(port->grf, port->pcie_status, &status);
>>> +        if ((status & (1 << 9))) {
>>
>> use a constant for the (1 << 9) [aka BIT(9)] please
>>
>>> +            dev_info(port->dev, "pll locked!\n");
>>
>> dev_dbg instead?
>
> yep
>
>>
>>> +            err = 0;
>>> +            break;
>>> +        }
>>> +    }
>>> +    if (err) {
>>> +        dev_err(port->dev, "pll lock timeout!\n");
>>> +        return err;
>>> +    }
>>> +    pcie_pb_wr_cfg(port, 0x10, 0x8);
>>> +    pcie_pb_wr_cfg(port, 0x12, 0x8);
>>> +
>>> +    err = -ETIMEDOUT;
>>> +    while (time_before(jiffies, timeout)) {
>>> +        regmap_read(port->grf, port->pcie_status, &status);
>>> +        if (!(status & (1 << 10))) {
>>
>> constant again
>>
>>> +            dev_info(port->dev, "pll output enable done!\n");
>>
>> dev_dbg or leave it out
>
> dev_dbg should be fine.
>
>>
>>> +            err = 0;
>>> +            break;
>>> +        }
>>> +    }
>>> +
>>> +    if (err) {
>>> +        dev_err(port->dev, "pll output enable timeout!\n");
>>> +        return err;
>>> +    }
>>> +
>>> +    regmap_write(port->grf, port->pcie_conf,
>>> +             (0x3f << 17) | (0x10 << 1));
>>> +    err = -EINVAL;
>>> +    while (time_before(jiffies, timeout)) {
>>> +        regmap_read(port->grf, port->pcie_status, &status);
>>> +        if ((status & (1 << 9))) {
>>> +            dev_info(port->dev, "pll relocked!\n");
>>> +            err = 0;
>>> +            break;
>>> +        }
>>> +    }
>>> +    if (err) {
>>> +        dev_err(port->dev, "pll relock timeout!\n");
>>> +        return err;
>>> +    }
>>
>> ------ phy_enable end ------
>>
>>
>>> +    err = reset_control_deassert(port->core_rst);
>>> +    if (err) {
>>> +        dev_err(port->dev, "deassert core_rst err %d\n", err);
>>> +        return err;
>>> +    }
>>> +    err = reset_control_deassert(port->mgmt_rst);
>>> +    if (err) {
>>> +        dev_err(port->dev, "deassert mgmt_rst err %d\n", err);
>>> +        return err;
>>> +    }
>>> +    err = reset_control_deassert(port->mgmt_sticky_rst);
>>> +    if (err) {
>>> +        dev_err(port->dev, "deassert mgmt_sticky_rst err %d\n", err);
>>> +        return err;
>>> +    }
>>> +    err = reset_control_deassert(port->pipe_rst);
>>> +    if (err) {
>>> +        dev_err(port->dev, "deassert pipe_rst err %d\n", err);
>>> +        return err;
>>> +    }
>>> +
>>> +    pcie_write(port, 1 << 17 | 1 << 1, PCIE_CLIENT_BASE);
>>> +
>>> +    gpiod_set_value(port->ep_gpio, 1);
>>> +    err = -ETIMEDOUT;
>>> +    while (time_before(jiffies, timeout)) {
>>> +        status = pcie_read(port, PCIE_CLIENT_BASIC_STATUS1);
>>> +        if (((status >> 20) & 0x3) == 0x3) {
>>> +            dev_info(port->dev, "pcie link training gen1 pass!\n");
>>> +            err = 0;
>>> +            break;
>>> +        }
>>> +    }
>>> +    if (err) {
>>> +        dev_err(port->dev, "pcie link training gen1 timeout!\n");
>>> +        return err;
>>> +    }
>>> +
>>> +    status = pcie_read(port, 0x9000d0);
>>> +    status |= 0x20;
>>> +    pcie_write(port, status, 0x9000d0);
>>
>> just to mention it again, bit handling as descriptive constant please and
>> also please give that register a name :-)
>
> will address this magic number all above using a new header file :)
>
>>
>> [...]
>>
>>> +static int rockchip_pcie_parse_dt(struct rockchip_pcie_port *port)
>>> +{
>>
>> [...]
>>
>>> +    port->lanes = 1;
>>> +    err = of_property_read_u32(node, "num-lanes", &port->lanes);
>>> +    if (!err && ((port->lanes == 0) ||
>>> +             (port->lanes == 3) ||
>>> +             (port->lanes > 4))) {
>>> +        dev_info(dev, "invalid num-lanes, default use one lane\n");
>>
>> dev_warn might be more appropriate
>
> sure.
>
>>
>>> +        port->lanes = 1;
>>> +    }
>>
>> [...]
>>
>>> +static void rockchip_pcie_msi_enable(struct rockchip_pcie_port *pp)
>>> +{
>>> +    struct device_node *msi_node;
>>> +
>>> +    msi_node = of_parse_phandle(pp->dev->of_node,
>>> +                    "msi-parent", 0);
>>
>> I would assume this should live in the general parse_dt function?
>> Also is that MSI enablement really allow to fail silently without any
>> affect
>> on the PCI functionality?
>
> yes, we should check this as well as CONFIG_PCI_MSI.
> Will fix it.
>
>
>>
>>> +    if (!msi_node)
>>> +        return;
>>> +
>>> +    pp->msi = of_pci_find_msi_chip_by_node(msi_node);
>>> +    of_node_put(msi_node);
>>> +
>>> +    if (pp->msi)
>>> +        pp->msi->dev = pp->dev;
>>> +}
>>
>> [...]
>>
>>> +static int rockchip_pcie_probe(struct platform_device *pdev)
>>> +{
>>> +    struct rockchip_pcie_port *port;
>>> +    struct device *dev = &pdev->dev;
>>> +    struct pci_bus *bus, *child;
>>> +    struct resource_entry *win;
>>> +    int reg_no;
>>> +    int err = 0;
>>> +    int irq;
>>> +    LIST_HEAD(res);
>>> +
>>> +    if (!dev->of_node)
>>> +        return -ENODEV;
>>> +
>>> +    port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
>>> +    if (!port)
>>> +        return -ENOMEM;
>>> +
>>> +    irq = platform_get_irq_byname(pdev, "pcie-sys");
>>> +    if (irq < 0) {
>>> +        dev_err(dev, "missing pcie_sys IRQ resource\n");
>>> +        return -EINVAL;
>>> +    }
>>
>> blank line
>>
>>> +    err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler,
>>> +                   IRQF_SHARED, "pcie-sys", port);
>>> +    if (err) {
>>> +        dev_err(dev, "failed to request pcie subsystem irq\n");
>>> +        return err;
>>> +    }
>>> +
>>> +    port->irq = platform_get_irq_byname(pdev, "pcie-legacy");
>>> +    if (port->irq < 0) {
>>> +        dev_err(dev, "missing pcie_legacy IRQ resource\n");
>>> +        return -EINVAL;
>>> +    }
>>
>> blank line
>>
>>> +    err = devm_request_irq(dev, port->irq,
>>> +                   rockchip_pcie_legacy_int_handler,
>>> +                   IRQF_SHARED,
>>> +                   "pcie-legacy",
>>> +                   port);
>>> +    if (err) {
>>> +        dev_err(&pdev->dev, "failed to request pcie-legacy irq\n");
>>> +        return err;
>>> +    }
>>> +
>>> +    irq = platform_get_irq_byname(pdev, "pcie-client");
>>> +    if (irq < 0) {
>>> +        dev_err(dev, "missing pcie-client IRQ resource\n");
>>> +        return -EINVAL;
>>> +    }
>>
>> blank line
>>
>>> +    err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler,
>>> +                   IRQF_SHARED, "pcie-client", port);
>>> +    if (err) {
>>> +        dev_err(dev, "failed to request pcie client irq\n");
>>> +        return err;
>>> +    }
>>> +
>>> +    port->dev = dev;
>>> +    err = rockchip_pcie_parse_dt(port);
>>> +    if (err) {
>>> +        dev_err(dev, "Parsing DT failed\n");
>>> +        return err;
>>> +    }
>>
>> rockchip_pcie_parse_dt already emits error messages that are a lot more
>> specific to the actual problem, so you don't need another error
>> message here
>> and can just return the error code.
>>
>
> okay.
>
>>
>>> +    err = rockchip_pcie_init_port(port);
>>> +    if (err)
>>> +        return err;
>>> +
>>> +    platform_set_drvdata(pdev, port);
>>> +
>>> +    rockchip_pcie_enable_interrupts(port);
>>> +    if (!IS_ENABLED(CONFIG_PCI_MSI)) {
>>> +        err = rockchip_pcie_init_irq_domain(port);
>>> +        if (err < 0)
>>> +            return err;
>>> +    }
>>> +
>>> +    err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff,
>>> +                           &res, &port->io_base);
>>> +    if (err)
>>> +        return err;
>>
>> add blank line
>>
>>
>> Heiko
>>
>>
>>
>
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Sun May 22 21:13:09 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Mon, 23 May 2016 12:13:09 +0800
Subject: [PATCH v5 0/5] Add enhanced strobe support for emmc version 5.1 or
 later
Message-ID: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>


Hello all,

This patch is going to support enhanced strobe function
for emmc version 5.1+ introduced by JEDEC recently.

Enchanced strobe is a optional function, so we add a new cap* for drivers to
decide whether to use it.

When introduing hs400 mode, JEDEC asks controllers to use data strobe line
to latch the data from emmc devives. But for cmd-reponse, not mentioned yet.
Since emmc version 5.1 published, JEDEC adds enhanced strobe function to deal
with cmd-response the same way as data-read. This feature is optional.

>From the spec(section 6.6.2.3), the standard scenario to select HS400 enhanced
strobe mode illustrated like this:
(1) set HS_TIMIMG (Highspeed)
(2) Host change freq to <= 52Mhz
(3) set the bus width to Enhanced strobe and DDR8Bit(CMD6), EXT_CSD[183] = 0x86
instead of 0x80
(4) set HS_TIMING to 0x3 (HS400)
(5) Host change freq to <= 200Mhz
(6) Host select HS400 enhanced strobe complete

I can't find a upstreamed controller claimed to support it, as well as the
mmc stack. But my "arasan,sdhci-5.1" actually supports this function. So I decide
to work for this part.

By looking into the SDHCI spec, I find there isn't any registers to enable the
enhanced strobe function. But from my "arasan,sdhci-5.1" databook, it describes a
register called VENDOR_REGISTER(0x78) to trigger this mode. So I guess other sdhci
variant drivers may also need s vendor specific register to deal with it.

If we are sure that our controller supports enhanced strobe mode, just add
mmc-hs400-enhanced-strobe in DT. Once emmc devices claims to support this mode,
we enable it automatically. Of course, other sdhci*/non-sdhci drivers should
implement/overwrite the prepare_enhanced_strobe by themselves. I believe all of the
platforms which need to support this mode should do some basic preparation for their
controllers. Currently I just limit the callback within ths scope of arasan,sdhci-5.1,
but I prone to believe arasan will use VENDOR_REGISTER to tirgger this mode from now on
because I do believe vendor will consider the registers' compatibility.

With this patchset applied, we can successfully run in HS400 enhanced strobe mode on
RK3399 platform with Samsung eMMC KLMBG2JENB-B041(v5.1, 16GB).

mmc1: new HS400 Enhanced strobe MMC card at address 0001
mmcblk0: mmc1:0001 AJNB4R 14.6 GiB
mmcblk0boot0: mmc1:0001 AJNB4R partition 1 4.00 MiB
mmcblk0boot1: mmc1:0001 AJNB4R partition 2 4.00 MiB
mmcblk0rpmb: mmc1:0001 AJNB4R partition 3 4.00 MiB

Also I check this patchset with removing some caps to make sure
all the init sequences for hs400/hs200/DDR52/HighSpeed is correct.


Changes in v5:
- avoid to call hs400_enhanced+_strobe in mmc_set_initial_state
  if no setting MMC_CAP2_HS400_ES.
- add Adrian's ack for patch[5/5]

Changes in v4:
- check avail_type with EXT_CSD_CARD_TYPE_HS400 instead of
  card_type
- check if host support 8-bit when selecting hs400es
- some minor fix suggested by Douglas and add his review tag

Changes in v3:
- remove helper function and shorten cap2 to MMC_CAP2_HS400_ES
- rename callback to hs400_enhanced_strobe and make it return void
- add enhanced_strobe in mmc_ios and pass it to hs400_enhanced_strobe
- disable host's enhanced strobe in mmc_set_initial_state
- remove bus checking after switching hs400es
- add new function for hs400es timing selection
- fix wrong judgement of mmc_card_hs400es

Changes in v2:
- switch to HS400ES from Highspeed mode directly

Shawn Lin (5):
  Documentation: mmc: add mmc-hs400-enhanced-strobe
  mmc: core: add mmc-hs400-enhanced-strobe support
  mmc: core: implement enhanced strobe support
  mmc: debugfs: add HS400 enhanced strobe description
  mmc: sdhci-of-arasan: implement enhanced strobe callback

 Documentation/devicetree/bindings/mmc/mmc.txt |  1 +
 drivers/mmc/core/bus.c                        |  3 +-
 drivers/mmc/core/core.c                       |  9 +++
 drivers/mmc/core/debugfs.c                    |  4 +-
 drivers/mmc/core/host.c                       |  2 +
 drivers/mmc/core/mmc.c                        | 84 ++++++++++++++++++++++++++-
 drivers/mmc/host/sdhci-of-arasan.c            | 20 +++++++
 include/linux/mmc/card.h                      |  1 +
 include/linux/mmc/host.h                      | 12 ++++
 include/linux/mmc/mmc.h                       |  3 +
 10 files changed, 135 insertions(+), 4 deletions(-)

-- 
2.3.7




From shawn.lin at rock-chips.com  Sun May 22 21:13:32 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Mon, 23 May 2016 12:13:32 +0800
Subject: [PATCH v5 1/5] Documentation: mmc: add mmc-hs400-enhanced-strobe
In-Reply-To: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463976812-29698-1-git-send-email-shawn.lin@rock-chips.com>

mmc-hs400-enhanced-strobe is used to claim that the
host can support hs400 mode with enhanced strobe
introduced by emmc 5.1 spec.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
Acked-by: Rob Herring <robh at kernel.org>
---

Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 Documentation/devicetree/bindings/mmc/mmc.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index ed23b9b..ecc007a 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -46,6 +46,7 @@ Optional properties:
 - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
 - mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
 - mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
+- mmc-hs400-enhanced-strobe: eMMC HS400 enhanced strobe mode is supported
 - dsr: Value the card's (optional) Driver Stage Register (DSR) should be
   programmed with. Valid range: [0 .. 0xffff].
 
-- 
2.3.7




From shawn.lin at rock-chips.com  Sun May 22 21:13:43 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Mon, 23 May 2016 12:13:43 +0800
Subject: [PATCH v5 2/5] mmc: core: add mmc-hs400-enhanced-strobe support
In-Reply-To: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463976823-29739-1-git-send-email-shawn.lin@rock-chips.com>

This patch introduce mmc-hs400-enhanced-strobe for platforms
which want to enable enhanced strobe function from DT if the
mmc host controller claims to support enhanced strobe.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

---

Changes in v5:
- avoid to call hs400_enhanced+_strobe in mmc_set_initial_state
  if no setting MMC_CAP2_HS400_ES.
- add Adrian's ack for patch[5/5]

Changes in v4:
- check avail_type with EXT_CSD_CARD_TYPE_HS400 instead of
  card_type
- check if host support 8-bit when selecting hs400es
- some minor fix suggested by Douglas and add his review tag

Changes in v3:
- remove helper function and shorten cap2 to MMC_CAP2_HS400_ES
- rename callback to hs400_enhanced_strobe and make it return void
- add enhanced_strobe in mmc_ios and pass it to hs400_enhanced_strobe
- disable host's enhanced strobe in mmc_set_initial_state
- remove bus checking after switching hs400es
- add new function for hs400es timing selection
- fix wrong judgement of mmc_card_hs400es

Changes in v2:
- switch to HS400ES from Highspeed mode directly

 drivers/mmc/core/host.c  | 2 ++
 include/linux/mmc/host.h | 1 +
 2 files changed, 3 insertions(+)

diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index e0a3ee1..45773e4 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -289,6 +289,8 @@ int mmc_of_parse(struct mmc_host *host)
 		host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
 	if (of_property_read_bool(np, "mmc-hs400-1_2v"))
 		host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
+	if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
+		host->caps2 |= MMC_CAP2_HS400_ES;
 
 	host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
 	if (host->dsr_req && (host->dsr & ~0xffff)) {
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 85800b4..2a06fb0 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -302,6 +302,7 @@ struct mmc_host {
 #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
 #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18)	/* No physical write protect pin, assume that card is always read-write */
 #define MMC_CAP2_NO_SDIO	(1 << 19)	/* Do not send SDIO commands during initialization */
+#define MMC_CAP2_HS400_ES	(1 << 20)	/* Host supports enhanced strobe */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
-- 
2.3.7




From shawn.lin at rock-chips.com  Sun May 22 21:13:55 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Mon, 23 May 2016 12:13:55 +0800
Subject: [PATCH v5 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463976835-29780-1-git-send-email-shawn.lin@rock-chips.com>

Controllers use data strobe line to latch data from devices
under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
introduces enhanced strobe mode for latching cmd response from
emmc devices to host controllers. This new feature is optional,
so it depends both on device's cap and host's cap to decide
whether to use it or not.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/mmc/core/bus.c   |  3 +-
 drivers/mmc/core/core.c  |  9 ++++++
 drivers/mmc/core/mmc.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/mmc/card.h |  1 +
 include/linux/mmc/host.h | 11 +++++++
 include/linux/mmc/mmc.h  |  3 ++
 6 files changed, 108 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 4bc48f1..c64266f 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
-		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
+		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
 			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
+			mmc_card_hs400es(card) ? "Enhanced strobe " : "",
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 99275e4..b0c1f07 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1127,6 +1127,15 @@ void mmc_set_initial_state(struct mmc_host *host)
 	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ios.timing = MMC_TIMING_LEGACY;
 	host->ios.drv_type = 0;
+	host->ios.enhanced_strobe = false;
+
+	/*
+	 * Make sure we are in non-enhanced strobe mode before we
+	 * actually enable it in ext_csd.
+	 */
+	if ((host->caps2 & MMC_CAP2_HS400_ES) &&
+	     host->ops->hs400_enhanced_strobe)
+		host->ops->hs400_enhanced_strobe(host, &host->ios);
 
 	mmc_set_ios(host);
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f99c47e..9dc91ba 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
 	}
 
+	if ((caps2 & MMC_CAP2_HS400_ES) &&
+	    card->ext_csd.strobe_support &&
+	    (avail_type & EXT_CSD_CARD_TYPE_HS400))
+		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			mmc_card_set_blockaddr(card);
 	}
 
+	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
 	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
 	mmc_select_card_type(card);
 
@@ -1216,6 +1222,78 @@ out_err:
 	return err;
 }
 
+static int mmc_select_hs400es(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+	u8 val;
+
+	if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
+		err = -ENOTSUPP;
+		goto out_err;
+	}
+
+	err = mmc_select_bus_width(card);
+	if (IS_ERR_VALUE(err))
+		goto out_err;
+
+	/* Switch card to HS mode */
+	err = mmc_select_hs(card);
+	if (err) {
+		pr_err("%s: switch to high-speed failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	err = mmc_switch_status(card);
+	if (err)
+		goto out_err;
+
+	/* Switch card to DDR with strobe bit */
+	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 val,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	/* Switch card to HS400 */
+	val = EXT_CSD_TIMING_HS400 |
+	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, val,
+			   card->ext_csd.generic_cmd6_time,
+			   true, false, true);
+	if (err) {
+		pr_err("%s: switch to hs400es failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	/* Set host controller to HS400 timing and frequency */
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+
+	/* Controller enable enhanced strobe function */
+	host->ios.enhanced_strobe = true;
+	if (host->ops->hs400_enhanced_strobe)
+		host->ops->hs400_enhanced_strobe(host, &host->ios);
+
+	err = mmc_switch_status(card);
+	if (err)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
+	       __func__, err);
+	return err;
+}
+
 static void mmc_select_driver_type(struct mmc_card *card)
 {
 	int card_drv_type, drive_strength, drv_type;
@@ -1297,7 +1375,7 @@ err:
 }
 
 /*
- * Activate High Speed or HS200 mode if supported.
+ * Activate High Speed, HS200 or HS400ES mode if supported.
  */
 static int mmc_select_timing(struct mmc_card *card)
 {
@@ -1306,7 +1384,9 @@ static int mmc_select_timing(struct mmc_card *card)
 	if (!mmc_can_ext_csd(card))
 		goto bus_speed;
 
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
+		err = mmc_select_hs400es(card);
+	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 		err = mmc_select_hs200(card);
 	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 		err = mmc_select_hs(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index eb0151b..22defc2 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -95,6 +95,7 @@ struct mmc_ext_csd {
 	u8			raw_partition_support;	/* 160 */
 	u8			raw_rpmb_size_mult;	/* 168 */
 	u8			raw_erased_mem_count;	/* 181 */
+	u8			strobe_support;		/* 184 */
 	u8			raw_ext_csd_structure;	/* 194 */
 	u8			raw_card_type;		/* 196 */
 	u8			raw_driver_strength;	/* 197 */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2a06fb0..0eabb72 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -19,6 +19,7 @@
 
 #include <linux/mmc/core.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -77,6 +78,8 @@ struct mmc_ios {
 #define MMC_SET_DRIVER_TYPE_A	1
 #define MMC_SET_DRIVER_TYPE_C	2
 #define MMC_SET_DRIVER_TYPE_D	3
+
+	bool enhanced_strobe;			/* hs400es selection */
 };
 
 struct mmc_host_ops {
@@ -143,6 +146,9 @@ struct mmc_host_ops {
 
 	/* Prepare HS400 target operating frequency depending host driver */
 	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
+	/* Prepare enhanced strobe depending host driver */
+	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
+					 struct mmc_ios *ios);
 	int	(*select_drive_strength)(struct mmc_card *card,
 					 unsigned int max_dtr, int host_drv,
 					 int card_drv, int *drv_type);
@@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
 	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
 }
 
+static inline bool mmc_card_hs400es(struct mmc_card *card)
+{
+	return card->host->ios.enhanced_strobe;
+}
+
 void mmc_retune_timer_stop(struct mmc_host *host);
 
 static inline void mmc_retune_needed(struct mmc_host *host)
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 15f2c4a..c376209 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -297,6 +297,7 @@ struct _mmc_csd {
 #define EXT_CSD_PART_CONFIG		179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
+#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
 #define EXT_CSD_POWER_CLASS		187	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
@@ -380,12 +381,14 @@ struct _mmc_csd {
 #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
 #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
 					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
 #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
 #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
+#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
 
 #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
 #define EXT_CSD_TIMING_HS	1	/* High speed */
-- 
2.3.7




From shawn.lin at rock-chips.com  Sun May 22 21:14:04 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Mon, 23 May 2016 12:14:04 +0800
Subject: [PATCH v5 4/5] mmc: debugfs: add HS400 enhanced strobe description
In-Reply-To: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463976844-29821-1-git-send-email-shawn.lin@rock-chips.com>

We introduce HS400 with enhanced strobe function, so we need
to add it for debug show.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/mmc/core/debugfs.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 9382a57..51d7c38 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -148,7 +148,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc HS200";
 		break;
 	case MMC_TIMING_MMC_HS400:
-		str = "mmc HS400";
+		mmc_card_hs400es(host->card) ?
+			(str = "mmc HS400 enhanced strobe") :
+			(str = "mmc HS400");
 		break;
 	default:
 		str = "invalid";
-- 
2.3.7




From shawn.lin at rock-chips.com  Sun May 22 21:14:13 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Mon, 23 May 2016 12:14:13 +0800
Subject: [PATCH v5 5/5] mmc: sdhci-of-arasan: implement enhanced strobe
 callback
In-Reply-To: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1463976853-29862-1-git-send-email-shawn.lin@rock-chips.com>

Currently sdhci-arasan 5.1 can support enhanced strobe function,
and we now limit it just for "arasan,sdhci-5.1". Add
mmc-hs400-enhanced-strobe in DT to enable the function if we're
sure our controller can support it.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
Acked-by: Adrian Hunter <adrian.hunter at intel.com>
Reviewed-by: Doug Anderson <dianders at chromium.org>
---

Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/mmc/host/sdhci-of-arasan.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index b6f4c1d..533e2bc 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -25,7 +25,9 @@
 #include "sdhci-pltfm.h"
 
 #define SDHCI_ARASAN_CLK_CTRL_OFFSET	0x2c
+#define SDHCI_ARASAN_VENDOR_REGISTER	0x78
 
+#define VENDOR_ENHANCED_STROBE		BIT(0)
 #define CLK_CTRL_TIMEOUT_SHIFT		16
 #define CLK_CTRL_TIMEOUT_MASK		(0xf << CLK_CTRL_TIMEOUT_SHIFT)
 #define CLK_CTRL_TIMEOUT_MIN_EXP	13
@@ -79,6 +81,21 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
 	}
 }
 
+static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
+					struct mmc_ios *ios)
+{
+	u32 vendor;
+	struct sdhci_host *host = mmc_priv(mmc);
+
+	vendor = readl(host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
+	if (ios->enhanced_strobe)
+		vendor |= VENDOR_ENHANCED_STROBE;
+	else
+		vendor &= ~VENDOR_ENHANCED_STROBE;
+
+	writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
+}
+
 static struct sdhci_ops sdhci_arasan_ops = {
 	.set_clock = sdhci_arasan_set_clock,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
@@ -245,6 +262,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev, "phy_power_on err.\n");
 			goto err_phy_power;
 		}
+
+		host->mmc_host_ops.hs400_enhanced_strobe =
+					sdhci_arasan_hs400_enhanced_strobe;
 	}
 
 	ret = sdhci_add_host(host);
-- 
2.3.7




From mark.yao at rock-chips.com  Sun May 22 23:10:16 2016
From: mark.yao at rock-chips.com (Mark yao)
Date: Mon, 23 May 2016 14:10:16 +0800
Subject: [PATCH 0/3] drm/rockchip: fix some sparse warnings
In-Reply-To: <20160510160356.1167-1-john@metanate.com>
References: <20160510160356.1167-1-john@metanate.com>
Message-ID: <57429EC8.4080207@rock-chips.com>

On 2016?05?11? 00:03, John Keeping wrote:
> The first patch wasn't found by sparse, but is something I noticed while
> in the area.  The following two fix all of the sparse warnings inside
> drm/rockchip.
>
> John Keeping (3):
>    drm/rockchip: dw_hdmi: remove unused #include
>    drm/rockchip: fb: add missing header
>    drm/rockchip: fix "should it be static?" warnings
>
>   drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c | 1 -
>   drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 ++--
>   drivers/gpu/drm/rockchip/rockchip_drm_fb.c  | 7 ++++---
>   drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 4 ++--
>   drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 2 +-
>   5 files changed, 9 insertions(+), 9 deletions(-)
>

Hi John

Sorry for reply late, this series of patches looks good for me, Applied 
to my branch.

Thanks.

-- 
?ark Yao




From mark.yao at rock-chips.com  Sun May 22 23:32:59 2016
From: mark.yao at rock-chips.com (Mark yao)
Date: Mon, 23 May 2016 14:32:59 +0800
Subject: [PATCH 1/2] drm/rockchip: vop: Do check if an update is pending
 during disable
In-Reply-To: <CAAObsKBXxb8ZS3CqLy4qsDRWLvT=w2ACANCcDLE5B47nRKtvBw@mail.gmail.com>
References: <1459937686-9142-1-git-send-email-tomeu.vizoso@collabora.com>
 <5707043D.6060706@rock-chips.com>
 <CAAObsKAeAjUP1retiZqo5geOK2OkVjKvSB6g6nvGTh_rdNiFJQ@mail.gmail.com>
 <570AFAC2.8080907@rock-chips.com>
 <CAAObsKCmPZBaSudVJy8BPThhoZw8VVqxicqsmc8diApajD57nA@mail.gmail.com>
 <CAAObsKBXxb8ZS3CqLy4qsDRWLvT=w2ACANCcDLE5B47nRKtvBw@mail.gmail.com>
Message-ID: <5742A41B.8030308@rock-chips.com>

On 2016?05?05? 17:34, Tomeu Vizoso wrote:
> On 20 April 2016 at 16:23, Tomeu Vizoso <tomeu.vizoso at collabora.com> wrote:
>> On 11 April 2016 at 03:15, Mark yao <mark.yao at rock-chips.com> wrote:
>>> On 2016?04?08? 18:54, Tomeu Vizoso wrote:
>>>> On 8 April 2016 at 03:07, Mark yao <mark.yao at rock-chips.com> wrote:
>>>>> On 2016?04?06? 18:14, Tomeu Vizoso wrote:
>>>>>
>>>>> When a plane is being disabled but it's still enabled, do check if the
>>>>> previous update has been completed by reading yrgb_mst back.
>>>>>
>>>>> Otherwise, pending pageflips would remain pending after a CRTC is
>>>>> disabled.
>>>>>
>>>>> Signed-off-by: Tomeu Vizoso <tomeu.vizoso at collabora.com>
>>>>> ---
>>>>>    drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 +++--
>>>>>    1 file changed, 3 insertions(+), 2 deletions(-)
>>>>>
>>>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>>> b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>>> index a9b1e8b5ac85..f46b1fd1887b 100644
>>>>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>>> @@ -1064,8 +1064,9 @@ static bool vop_win_pending_is_complete(struct
>>>>> vop_win
>>>>> *vop_win)
>>>>>     struct vop_plane_state *state = to_vop_plane_state(plane->state);
>>>>>     dma_addr_t yrgb_mst;
>>>>>
>>>>> - if (!state->enable)
>>>>> - return VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0;
>>>>> + if (!state->enable &&
>>>>> +    VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0)
>>>>> + return true;
>>>>>
>>>>>
>>>>> It is wrong, the patch would cause a bug.
>>>>>
>>>>> when state->enable is 0, check yrgb_mst == state->yrgb_mst always be
>>>>> true,
>>>>> because state->yrgb_mst not update on plane disabled funtion, that would
>>>>> cause iommu crash.
>>>> Sorry, but I don't understand where's the bug and what could cause
>>>> that crash. What the existing code was doing is saying that a pageflip
>>>> event is still pending if we have told the plane to disable but for
>>>> some reason it hasn't yet.
>>>>
>>>> With this modification, if we read back that it's already disabled, we
>>>> return true as before. But if we read back that it isn't disabled yet,
>>>> then we still check the fb pointers and compare them.
>>>>
>>>> The iommu mapping is removed when the _CRTC_ is disabled, and what
>>>> this series does is to wait for the pending pageflip to finish before
>>>> conitnuing with CRTC disablement.
>>>
>>> the iommu mapping will unmap after plane disabled, we need sure that the
>>> plane really disabled before unmap, if not, the unmap may call before plane
>>> really disable, vop may access unmap address, then would get iommu page
>>> fault.
>> Sorry, but I still don't see the error condition that you are
>> describing. AFAICS, the unmap will happen after the last pageflip has
>> completed.
>>
>>>>> About pending pageflips would remain pending, can you  describe more info
>>>>> about it? I think those pending pageflips should be ignore when CRTC is
>>>>> disabled.
>>>> Well, right now in rockchip-drm pending pageflips won't be ignored
>>>> when a CRTC is disabled, but will be delivered when it's re-enabled.
>>>>
>>>> If they would be to be ignored (understanding that as dropped), that
>>>> would require modifications to clients so they keep track of which fbs
>>>> were used in a particular crtc and destroy them when the crtc is
>>>> disabled, but that would be incorrect when using the i915 DRM driver
>>>> (I also assume others do the same). Given that the pageflip ioctl
>>>> isn't driver-specific, I think there cannot be such a difference in
>>>> behavior between drivers.
>>>>
>>>> With the current behavior (pending pageflip events being delayed until
>>>> the CRTC is enabled again), compositors and other clients will be
>>>> holding on to the fb in the pending pageflip until an arbitrary point
>>>> in the future that may not ever come. To me that sounds like a serious
>>>> modification of the assumptions on fb lifecycle that might not be
>>>> warranted.
>>>>
>>>> So in summary, even if I haven't found any explicit documentation on
>>>> this, I think the ABI is that any pending pageflips are to be
>>>> delivered when that CRTC is being disabled and not later.
>>>
>>> on drivers/gpu/drm/rockchip/rockchip_drm_fb.c
>>>
>>> drm_atomic_helper_commit_planes(dev, state, true);
>>> rockchip_atomic_wait_for_complete(dev, state);
>>>
>>> We set active_only = true, I think planes can only update when crtc is
>>> active. and rockchip_atomic_wait_for_complete only wait when crtc is active.
>> That's fine, but if a pageflip is pending when the client requests the
>> CRTC to be disabled, we need to wait for the event to be emitted
>> before we actually disable the HW.
> Hi Mark,
>
> could you tell me if you agree that there's a bug that needs to be
> solved, and if so, what do you think we should do about it?
Hi Tomeu

Sorry for reply late.
I don't agree the changes:

- if (!state->enable)
- return VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0;
+ if (!state->enable &&
+    VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0)
+ return true;

This changes actually would lead a bug.
when we disable a plane, the vop_win_pending_is_complete would always 
return true, That is not allowed, would cause fb free too early.

Does this patch is needed for "[PATCH 2/2] drm/rockchip: vop: Wait for 
pending events when disabling a CRTC"

Thanks.

> Thanks,
>
> Tomeu
>
>> Regards,
>>
>> Tomeu
>>
>>> Thanks.
>>>
>>>> Thanks,
>>>>
>>>> Tomeu
>>>>
>>>>> Thanks.
>>>>>
>>>>>
>>>>>     yrgb_mst = VOP_WIN_GET_YRGBADDR(vop_win->vop, vop_win->data);
>>>>>
>>>>>
>>>>>
>>>>> --
>>>>> ?ark Yao
>>>>>
>>>>>
>>>>> _______________________________________________
>>>>> dri-devel mailing list
>>>>> dri-devel at lists.freedesktop.org
>>>>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>>>>>
>>>>
>>>
>>> --
>>> ?ark Yao
>>>
>>>
>>> _______________________________________________
>>> dri-devel mailing list
>>> dri-devel at lists.freedesktop.org
>>> https://lists.freedesktop.org/mailman/listinfo/dri-devel
>
>


-- 
?ark Yao




From mark.yao at rock-chips.com  Sun May 22 23:51:23 2016
From: mark.yao at rock-chips.com (Mark yao)
Date: Mon, 23 May 2016 14:51:23 +0800
Subject: [GIT PULL] drm/rockchip: new feature to support rk3399 vop and some
 fixes
Message-ID: <5742A86B.5050307@rock-chips.com>

Hi Dave

This series of patches add rk3399 vop support and fix some sparse warnings.

Now seems no doubt on them, and looks good for me, So I'd like you can 
land them.

Thanks.

The following changes since commit fcee59065e58498682c60069cc6fb90694bab27e:

   drm: Nuke ->vblank_disable_allowed (2016-05-21 07:03:31 +1000)

are available in the git repository at:

   https://github.com/markyzq/kernel-drm-rockchip.git 
drm-rockchip-next-2016-05-23

for you to fetch changes up to cc69ebfafff43f49eec3ded18794dc9c3c8c0735:

   dt-bindings: add documentation for Rockchip rk3399 display 
controllers (2016-05-23 14:39:37 +0800)

----------------------------------------------------------------
John Keeping (3):
       drm/rockchip: dw_hdmi: remove unused #include
       drm/rockchip: fb: add missing header
       drm/rockchip: fix "should it be static?" warnings

Mark Yao (5):
       drm/rockchip: sort registers define by chip's number
       dt-bindings: sort Rockchip vop compatible by chip's number
       drm/rockchip: vop: introduce VOP_REG_MASK
       drm/rockchip: vop: add rk3399 vop support
       dt-bindings: add documentation for Rockchip rk3399 display 
controllers

  Documentation/devicetree/bindings/display/rockchip/rockchip-vop.txt 
|   7 ++-
  drivers/gpu/drm/rockchip/dw_hdmi-rockchip.c |   1 -
  drivers/gpu/drm/rockchip/rockchip_drm_drv.c |   4 +-
  drivers/gpu/drm/rockchip/rockchip_drm_fb.c |   7 ++-
  drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  64 ++++++++++---------
  drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   5 ++
  drivers/gpu/drm/rockchip/rockchip_vop_reg.c | 238 
+++++++++++++++++++++++++++++++++++++++++++++++++---------------------
  drivers/gpu/drm/rockchip/rockchip_vop_reg.h | 279 
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
  8 files changed, 456 insertions(+), 149 deletions(-)

-- 
?ark Yao




From caesar.upstream at gmail.com  Mon May 23 00:32:39 2016
From: caesar.upstream at gmail.com (Caesar Wang)
Date: Mon, 23 May 2016 15:32:39 +0800
Subject: [PATCH v2 0/5] Thermal: Support for hardware-tracked trip points
In-Reply-To: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
Message-ID: <5742B217.4080405@gmail.com>

Hello Eduardo & 'Zhang Rui'

Do we have the chance to merge this series patches for next kernel?
I had picked them up in my github, and tested for a period of time with 
rockchip inside kernel.

Let me know if someone have some suggestions or against opinios.
Thanks,

-Caesar
On 2016?05?03? 17:33, Caesar Wang wrote:
> The history patches come from Mikko and Sascha.
> http://thread.gmane.org/gmane.linux.power-management.general/59451
>
> Now, I pick them up to continue upstream.
> Nevermind!
>
> This series history patches:
> v1: https://lkml.org/lkml/2016/4/24/227
>
> This series adds support for hardware trip points. It picks up earlier
> work from Mikko Perttunen. Mikko implemented hardware trip points as part
> of the device tree support. It was suggested back then to move the
> functionality to the thermal core instead of putting more code into the
> device tree support. This series does exactly that.
>
> This series patches rebase the conflicts.
> Note that the hardware-tracked trip points are very well tested currently.
>
> Verified and tested on https://github.com/Caesar-github/rockchip/tree/wip/fixes-thermal-0503
> That's based on linux-kernel 20160502.
> .Linux version 4.6.0-rc6-next-20160502-08922-g860ed34 (wxt at nb)
>
>
> Changes in v2:
> - update the sysfs-api.txt for set_trips
> - add the commit in patch[v2 2/5].
> - Update the commit for patch[v2 4/5].
>
> Caesar Wang (1):
>    thermal: rockchip: add the set_trips function
>
> Sascha Hauer (4):
>    thermal: Add support for hardware-tracked trip points
>    thermal: of: implement .set_trips for device tree thermal zones
>    thermal: streamline get_trend callbacks
>    thermal: bang-bang governor: act on lower trip boundary
>
>   Documentation/thermal/sysfs-api.txt                |  7 +++
>   drivers/thermal/gov_bang_bang.c                    |  2 +-
>   drivers/thermal/of-thermal.c                       | 23 +++++-----
>   drivers/thermal/rockchip_thermal.c                 | 39 ++++++++++++++++
>   drivers/thermal/thermal_core.c                     | 52 ++++++++++++++++++++++
>   drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 25 ++++-------
>   include/linux/thermal.h                            |  9 +++-
>   7 files changed, 128 insertions(+), 29 deletions(-)
>



From heiko at sntech.de  Mon May 23 02:28:32 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 23 May 2016 11:28:32 +0200
Subject: [PATCH 1/5] iommu/rockchip: fix devm_request_irq and
 devm_free_irq parameter
In-Reply-To: <1463967439-13354-2-git-send-email-zhengsq@rock-chips.com>
References: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
 <1463967439-13354-2-git-send-email-zhengsq@rock-chips.com>
Message-ID: <3963127.FSql0rTeZT@phil>

Am Montag, 23. Mai 2016, 09:37:15 schrieb Shunqian Zheng:
> From: Simon <xxm at rock-chips.com>

generally a "firstname surename <mail>" is expected, so a first name is not 
really enough.

> 
> When rk_iommu_attach_device or rk_iommu_detach_device be called, the
> second parameter "dev" represent the device who own the iommu, so it is
> not resonable using "dev" for devm_request_irq's first parameter. To
> avoid potential error, we must use iommu device itself "iommu->dev"
> instead, the same as devm_free_irq.
> 
> Signed-off-by: Simon <xxm at rock-chips.com>

same here, and the person sending in the patch also needs a signed-off-by 
line, so that should look like

Signed-off-by: Simon <xxm at rock-chips.com>
Signed-off-by: Shunqian Zheng <zhengsq at rock-chips.com>

The same applies of course for all other affected patches of this series.


After looking at the iommu code, I think the change itself looks sane, so
Reviewed-by: Heiko Stuebner <heiko at sntech.de>

although I wonder what we need the devm_* for if we request and free the 
irqs manually all the time anyway?


Heiko

> ---
>  drivers/iommu/rockchip-iommu.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/iommu/rockchip-iommu.c
> b/drivers/iommu/rockchip-iommu.c index c7d6156..ec0ce62 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -807,7 +807,7 @@ static int rk_iommu_attach_device(struct iommu_domain
> *domain,
> 
>  	iommu->domain = domain;
> 
> -	ret = devm_request_irq(dev, iommu->irq, rk_iommu_irq,
> +	ret = devm_request_irq(iommu->dev, iommu->irq, rk_iommu_irq,
>  			       IRQF_SHARED, dev_name(dev), iommu);
>  	if (ret)
>  		return ret;
> @@ -860,7 +860,7 @@ static void rk_iommu_detach_device(struct iommu_domain
> *domain, }
>  	rk_iommu_disable_stall(iommu);
> 
> -	devm_free_irq(dev, iommu->irq, iommu);
> +	devm_free_irq(iommu->dev, iommu->irq, iommu);
> 
>  	iommu->domain = NULL;



From robin.murphy at arm.com  Mon May 23 03:44:14 2016
From: robin.murphy at arm.com (Robin Murphy)
Date: Mon, 23 May 2016 11:44:14 +0100
Subject: [PATCH 4/5] iommu/rockchip: add ARM64 cache flush operation for
 iommu
In-Reply-To: <1463967439-13354-5-git-send-email-zhengsq@rock-chips.com>
References: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
 <1463967439-13354-5-git-send-email-zhengsq@rock-chips.com>
Message-ID: <5742DEFE.1040902@arm.com>

On 23/05/16 02:37, Shunqian Zheng wrote:
> From: Simon <xxm at rock-chips.com>
>
> Signed-off-by: Simon <xxm at rock-chips.com>
> ---
>   drivers/iommu/rockchip-iommu.c | 4 ++++
>   1 file changed, 4 insertions(+)
>
> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> index 043d18c..1741b65 100644
> --- a/drivers/iommu/rockchip-iommu.c
> +++ b/drivers/iommu/rockchip-iommu.c
> @@ -95,12 +95,16 @@ struct rk_iommu {
>
>   static inline void rk_table_flush(u32 *va, unsigned int count)
>   {
> +#if defined(CONFIG_ARM)
>   	phys_addr_t pa_start = virt_to_phys(va);
>   	phys_addr_t pa_end = virt_to_phys(va + count);
>   	size_t size = pa_end - pa_start;
>
>   	__cpuc_flush_dcache_area(va, size);
>   	outer_flush_range(pa_start, pa_end);
> +#elif defined(CONFIG_ARM64)
> +	__dma_flush_range(va, va + count);
> +#endif

Ugh, please don't use arch-private cache maintenance functions directly 
from a driver. Allocating/mapping page tables to be read by the IOMMU is 
still DMA, so using the DMA APIs is the correct way to manage them, 
*especially* if it needs to work across multiple architectures.

Robin.

>   }
>
>   static struct rk_iommu_domain *to_rk_domain(struct iommu_domain *dom)
>



From wsy2220 at gmail.com  Mon May 23 04:36:09 2016
From: wsy2220 at gmail.com (Shuyu Wei)
Date: Mon, 23 May 2016 19:36:09 +0800
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <57419853.9050701@gmx.de>
References: <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com>
 <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com>
 <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm> <5740E82F.8040903@gmx.de>
 <20160522091742.GA8681@debian-dorm> <57419853.9050701@gmx.de>
Message-ID: <20160523113609.GA21019@debian-dorm>

On Sun, May 22, 2016 at 01:30:27PM +0200, Lino Sanfilippo wrote:
> 
> Thanks for testing. However that extra check for skb not being NULL should not be
> necessary if the code were correct. The changes I suggested were all about having
> skb and info consistent with txbd_curr.
> But I just realized that there is still a big flaw in the last changes. While
> tx() looks correct now (we first set up the descriptor and assign the skb and _then_
> advance txbd_curr) tx_clean still is not:
> 
> We _first_ have to read tx_curr and _then_ read the corresponding descriptor and its skb.
> (The last patch implemented just the reverse - and thus wrong - order, first get skb and 
> descriptor and then read tx_curr).
> 
> So the patch below hopefully handles also tx_clean correctly. Could you please do once more a test
> with this one?

Hi Lino, 
This patch worked after a whole night of stress testing.

> > 
> > After further test, my patch to barrier timestamp() didn't work.
> > Just like the original code in the tree, the emac still got stuck under
> > high load, even if I changed the smp_wmb() to dma_wmb(). So the original
> > code do have race somewhere.
> 
> So to make this clear: with the current code in net-next you still see a problem (lockup), right?
Yes, I mean the mainline kernel, which should be the same as net-next.


> > ... and why Francois' fix worked. Please be patient with me :-).
> 
> So which fix(es) exactly work for you and solve your lockup issue?
I mean the patch below, starting this thread.

diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index a3a9392..df3dfef 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -153,9 +153,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 {
 	struct arc_emac_priv *priv = netdev_priv(ndev);
 	struct net_device_stats *stats = &ndev->stats;
-	unsigned int i;
 
-	for (i = 0; i < TX_BD_NUM; i++) {
+	while (priv->txbd_dirty != priv->txbd_curr) {
 		unsigned int *txbd_dirty = &priv->txbd_dirty;
 		struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
 		struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
@@ -685,13 +684,15 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
 	wmb();
 
 	skb_tx_timestamp(skb);
+	priv->tx_buff[*txbd_curr].skb = skb;
+
+	dma_wmb();
 
 	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
 	/* Make sure info word is set */
 	wmb();
 
-	priv->tx_buff[*txbd_curr].skb = skb;
 
 	/* Increment index to point to the next BD */
 	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;




From ykk at rock-chips.com  Mon May 23 06:10:56 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Mon, 23 May 2016 21:10:56 +0800
Subject: [PATCH 0/3] Add the eDP/VOP device node for rk3399
Message-ID: <1464009056-32158-1-git-send-email-ykk@rock-chips.com>

This thread is rely on Mark's VOP thread[1] and Yakir's eDP thread[2].

[1]: https://lkml.org/lkml/2016/4/20/36
[2]: https://patchwork.freedesktop.org/patch/83406/


Mark Yao (1):
  arm64: dts: rockchip: add VOP and VOP iommu node for rk3399

Yakir Yang (2):
  arm64: dts: rockchip: add eDP device node for rk3399
  arm64: dts: rockchip: add backlight support for rk3399 evb board

 arch/arm64/boot/dts/rockchip/rk3399-evb.dts |  40 ++++++++++
 arch/arm64/boot/dts/rockchip/rk3399.dtsi    | 110 ++++++++++++++++++++++++++++
 2 files changed, 150 insertions(+)

-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 06:11:10 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Mon, 23 May 2016 21:11:10 +0800
Subject: [PATCH 1/3] arm64: dts: rockchip: add VOP and VOP iommu node for
 rk3399
In-Reply-To: <1464009056-32158-1-git-send-email-ykk@rock-chips.com>
References: <1464009056-32158-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464009070-32215-1-git-send-email-ykk@rock-chips.com>

From: Mark Yao <mark.yao at rock-chips.com>

Signed-off-by: Mark Yao <mark.yao at rock-chips.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 58 ++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a..54e5c25 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -543,6 +543,64 @@
 		status = "disabled";
 	};
 
+	vopl: vop at ff8f0000 {
+		compatible = "rockchip,rk3399-vop-lit";
+		reg = <0x0 0xff8f0000 0x0 0x3efc>;
+		interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
+		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
+		resets = <&cru SRST_A_VOP1>, <&cru SRST_H_VOP1>, <&cru SRST_D_VOP1>;
+		reset-names = "axi", "ahb", "dclk";
+		iommus = <&vopl_mmu>;
+		status = "disabled";
+
+		vopl_out: port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+
+	vopl_mmu: iommu at ff8f3f00 {
+		compatible = "rockchip,iommu";
+		reg = <0x0 0xff8f3f00 0x0 0x100>;
+		interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "vopl_mmu";
+		#iommu-cells = <0>;
+		status = "disabled";
+	};
+
+	vopb: vop at ff900000 {
+		compatible = "rockchip,rk3399-vop-big";
+		reg = <0x0 0xff900000 0x0 0x3efc>;
+		interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
+		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
+		resets = <&cru SRST_A_VOP0>, <&cru SRST_H_VOP0>, <&cru SRST_D_VOP0>;
+		reset-names = "axi", "ahb", "dclk";
+		iommus = <&vopb_mmu>;
+		status = "disabled";
+
+		vopb_out: port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+
+	vopb_mmu: iommu at ff903f00 {
+		compatible = "rockchip,iommu";
+		reg = <0x0 0xff903f00 0x0 0x100>;
+		interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "vopb_mmu";
+		#iommu-cells = <0>;
+		status = "disabled";
+	};
+
+	display_subsystem: display-subsystem {
+		compatible = "rockchip,display-subsystem";
+		ports = <&vopl_out>, <&vopb_out>;
+		status = "disabled";
+	};
+
 	pinctrl: pinctrl {
 		compatible = "rockchip,rk3399-pinctrl";
 		rockchip,grf = <&grf>;
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 06:11:21 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Mon, 23 May 2016 21:11:21 +0800
Subject: [PATCH 2/3] arm64: dts: rockchip: add eDP device node for rk3399
In-Reply-To: <1464009056-32158-1-git-send-email-ykk@rock-chips.com>
References: <1464009056-32158-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464009081-32268-1-git-send-email-ykk@rock-chips.com>

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 52 ++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 54e5c25..be322db 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -557,6 +557,11 @@
 		vopl_out: port {
 			#address-cells = <1>;
 			#size-cells = <0>;
+
+			vopl_out_edp: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&edp_in_vopl>;
+			};
 		};
 	};
 
@@ -583,6 +588,11 @@
 		vopb_out: port {
 			#address-cells = <1>;
 			#size-cells = <0>;
+
+			vopb_out_edp: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&edp_in_vopb>;
+			};
 		};
 	};
 
@@ -595,6 +605,41 @@
 		status = "disabled";
 	};
 
+	edp: edp at ff970000 {
+		compatible = "rockchip,rk3399-edp";
+		reg = <0x0 0xff970000 0x0 0x8000>;
+		interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru PCLK_EDP>, <&cru PCLK_EDP_CTRL>;
+		clock-names = "dp", "pclk";
+		resets = <&cru SRST_P_EDP_CTRL>;
+		reset-names = "dp";
+		rockchip,grf = <&grf>;
+		status = "disabled";
+		pinctrl-names = "default";
+		pinctrl-0 = <&edp_hpd>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			edp_in: port at 0 {
+				reg = <0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				edp_in_vopb: endpoint at 0 {
+					reg = <0>;
+					remote-endpoint = <&vopb_out_edp>;
+				};
+
+				edp_in_vopl: endpoint at 1 {
+					reg = <1>;
+					remote-endpoint = <&vopl_out_edp>;
+				};
+			};
+		};
+	};
+
 	display_subsystem: display-subsystem {
 		compatible = "rockchip,display-subsystem";
 		ports = <&vopl_out>, <&vopb_out>;
@@ -1067,5 +1112,12 @@
 					<1 14 RK_FUNC_1 &pcfg_pull_none>;
 			};
 		};
+
+		edp {
+			edp_hpd: edp-hpd {
+				rockchip,pins =
+					<4 23 RK_FUNC_2 &pcfg_pull_none>;
+			};
+		};
 	};
 };
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 06:11:30 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Mon, 23 May 2016 21:11:30 +0800
Subject: [PATCH 3/3] arm64: dts: rockchip: add backlight support for rk3399
 evb board
In-Reply-To: <1464009056-32158-1-git-send-email-ykk@rock-chips.com>
References: <1464009056-32158-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464009090-32322-1-git-send-email-ykk@rock-chips.com>

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 40 +++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
index 1a3eb14..31d9e27 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
@@ -75,6 +75,46 @@
 		regulator-always-on;
 		regulator-boot-on;
 	};
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm0 0 25000 0>;
+		brightness-levels = <
+			  0   1   2   3   4   5   6   7
+			  8   9  10  11  12  13  14  15
+			 16  17  18  19  20  21  22  23
+			 24  25  26  27  28  29  30  31
+			 32  33  34  35  36  37  38  39
+			 40  41  42  43  44  45  46  47
+			 48  49  50  51  52  53  54  55
+			 56  57  58  59  60  61  62  63
+			 64  65  66  67  68  69  70  71
+			 72  73  74  75  76  77  78  79
+			 80  81  82  83  84  85  86  87
+			 88  89  90  91  92  93  94  95
+			 96  97  98  99 100 101 102 103
+			104 105 106 107 108 109 110 111
+			112 113 114 115 116 117 118 119
+			120 121 122 123 124 125 126 127
+			128 129 130 131 132 133 134 135
+			136 137 138 139 140 141 142 143
+			144 145 146 147 148 149 150 151
+			152 153 154 155 156 157 158 159
+			160 161 162 163 164 165 166 167
+			168 169 170 171 172 173 174 175
+			176 177 178 179 180 181 182 183
+			184 185 186 187 188 189 190 191
+			192 193 194 195 196 197 198 199
+			200 201 202 203 204 205 206 207
+			208 209 210 211 212 213 214 215
+			216 217 218 219 220 221 222 223
+			224 225 226 227 228 229 230 231
+			232 233 234 235 236 237 238 239
+			240 241 242 243 244 245 246 247
+			248 249 250 251 252 253 254 255>;
+		default-brightness-level = <200>;
+		enable-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
+	};
 };
 
 &pwm0 {
-- 
1.9.1




From heiko at sntech.de  Mon May 23 06:18:53 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 23 May 2016 15:18:53 +0200
Subject: [PATCH 1/3] arm64: dts: rockchip: add VOP and VOP iommu node for
 rk3399
In-Reply-To: <1464009070-32215-1-git-send-email-ykk@rock-chips.com>
References: <1464009056-32158-1-git-send-email-ykk@rock-chips.com>
 <1464009070-32215-1-git-send-email-ykk@rock-chips.com>
Message-ID: <2088899.KxOSoPueyv@phil>

Am Montag, 23. Mai 2016, 21:11:10 schrieb Yakir Yang:
> From: Mark Yao <mark.yao at rock-chips.com>

Please always at least provide some minimal patch description. Something 
like

--- 8< ---
Add the core display-subsystem node and the two display controllers
available on the rk3399
--- 8< ---

applies to the other two patches as well.

> Signed-off-by: Mark Yao <mark.yao at rock-chips.com>
> Signed-off-by: Yakir Yang <ykk at rock-chips.com>
> 
> Signed-off-by: Yakir Yang <ykk at rock-chips.com>

one Signed-off-by from Yakir to much ;-)

Otherwise all 3 look good, but we need to of course wait for the code-parts 
to be in place.


Heiko

> ---
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi | 58
> ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index 46f325a..54e5c25 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -543,6 +543,64 @@
>  		status = "disabled";
>  	};
> 
> +	vopl: vop at ff8f0000 {
> +		compatible = "rockchip,rk3399-vop-lit";
> +		reg = <0x0 0xff8f0000 0x0 0x3efc>;
> +		interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
> +		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
> +		resets = <&cru SRST_A_VOP1>, <&cru SRST_H_VOP1>, <&cru SRST_D_VOP1>;
> +		reset-names = "axi", "ahb", "dclk";
> +		iommus = <&vopl_mmu>;
> +		status = "disabled";
> +
> +		vopl_out: port {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +	};
> +
> +	vopl_mmu: iommu at ff8f3f00 {
> +		compatible = "rockchip,iommu";
> +		reg = <0x0 0xff8f3f00 0x0 0x100>;
> +		interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
> +		interrupt-names = "vopl_mmu";
> +		#iommu-cells = <0>;
> +		status = "disabled";
> +	};
> +
> +	vopb: vop at ff900000 {
> +		compatible = "rockchip,rk3399-vop-big";
> +		reg = <0x0 0xff900000 0x0 0x3efc>;
> +		interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
> +		clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
> +		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
> +		resets = <&cru SRST_A_VOP0>, <&cru SRST_H_VOP0>, <&cru SRST_D_VOP0>;
> +		reset-names = "axi", "ahb", "dclk";
> +		iommus = <&vopb_mmu>;
> +		status = "disabled";
> +
> +		vopb_out: port {
> +			#address-cells = <1>;
> +			#size-cells = <0>;
> +		};
> +	};
> +
> +	vopb_mmu: iommu at ff903f00 {
> +		compatible = "rockchip,iommu";
> +		reg = <0x0 0xff903f00 0x0 0x100>;
> +		interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
> +		interrupt-names = "vopb_mmu";
> +		#iommu-cells = <0>;
> +		status = "disabled";
> +	};
> +
> +	display_subsystem: display-subsystem {
> +		compatible = "rockchip,display-subsystem";
> +		ports = <&vopl_out>, <&vopb_out>;
> +		status = "disabled";
> +	};
> +
>  	pinctrl: pinctrl {
>  		compatible = "rockchip,rk3399-pinctrl";
>  		rockchip,grf = <&grf>;



From ykk at rock-chips.com  Mon May 23 06:26:48 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Mon, 23 May 2016 21:26:48 +0800
Subject: [PATCH 1/3] arm64: dts: rockchip: add VOP and VOP iommu node for
 rk3399
In-Reply-To: <2088899.KxOSoPueyv@phil>
References: <1464009056-32158-1-git-send-email-ykk@rock-chips.com>
 <1464009070-32215-1-git-send-email-ykk@rock-chips.com>
 <2088899.KxOSoPueyv@phil>
Message-ID: <57430518.6090708@rock-chips.com>


On 05/23/2016 09:18 PM, Heiko Stuebner wrote:
> Am Montag, 23. Mai 2016, 21:11:10 schrieb Yakir Yang:
>> From: Mark Yao <mark.yao at rock-chips.com>
> Please always at least provide some minimal patch description. Something
> like
>
> --- 8< ---
> Add the core display-subsystem node and the two display controllers
> available on the rk3399
> --- 8< ---
>
> applies to the other two patches as well.
Okay  ;)
>> Signed-off-by: Mark Yao <mark.yao at rock-chips.com>
>> Signed-off-by: Yakir Yang <ykk at rock-chips.com>
>>
>> Signed-off-by: Yakir Yang <ykk at rock-chips.com>
> one Signed-off-by from Yakir to much ;-)
Done
> Otherwise all 3 look good, but we need to of course wait for the code-parts
> to be in place.
Thanks,

- Yakir
>
> Heiko
>
>> ---
>>   arch/arm64/boot/dts/rockchip/rk3399.dtsi | 58
>> ++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+)
>>
>> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
>> b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index 46f325a..54e5c25 100644
>> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
>> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
>> @@ -543,6 +543,64 @@
>>   		status = "disabled";
>>   	};
>>
>> +	vopl: vop at ff8f0000 {
>> +		compatible = "rockchip,rk3399-vop-lit";
>> +		reg = <0x0 0xff8f0000 0x0 0x3efc>;
>> +		interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
>> +		clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
>> +		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
>> +		resets = <&cru SRST_A_VOP1>, <&cru SRST_H_VOP1>, <&cru SRST_D_VOP1>;
>> +		reset-names = "axi", "ahb", "dclk";
>> +		iommus = <&vopl_mmu>;
>> +		status = "disabled";
>> +
>> +		vopl_out: port {
>> +			#address-cells = <1>;
>> +			#size-cells = <0>;
>> +		};
>> +	};
>> +
>> +	vopl_mmu: iommu at ff8f3f00 {
>> +		compatible = "rockchip,iommu";
>> +		reg = <0x0 0xff8f3f00 0x0 0x100>;
>> +		interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
>> +		interrupt-names = "vopl_mmu";
>> +		#iommu-cells = <0>;
>> +		status = "disabled";
>> +	};
>> +
>> +	vopb: vop at ff900000 {
>> +		compatible = "rockchip,rk3399-vop-big";
>> +		reg = <0x0 0xff900000 0x0 0x3efc>;
>> +		interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
>> +		clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
>> +		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
>> +		resets = <&cru SRST_A_VOP0>, <&cru SRST_H_VOP0>, <&cru SRST_D_VOP0>;
>> +		reset-names = "axi", "ahb", "dclk";
>> +		iommus = <&vopb_mmu>;
>> +		status = "disabled";
>> +
>> +		vopb_out: port {
>> +			#address-cells = <1>;
>> +			#size-cells = <0>;
>> +		};
>> +	};
>> +
>> +	vopb_mmu: iommu at ff903f00 {
>> +		compatible = "rockchip,iommu";
>> +		reg = <0x0 0xff903f00 0x0 0x100>;
>> +		interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
>> +		interrupt-names = "vopb_mmu";
>> +		#iommu-cells = <0>;
>> +		status = "disabled";
>> +	};
>> +
>> +	display_subsystem: display-subsystem {
>> +		compatible = "rockchip,display-subsystem";
>> +		ports = <&vopl_out>, <&vopb_out>;
>> +		status = "disabled";
>> +	};
>> +
>>   	pinctrl: pinctrl {
>>   		compatible = "rockchip,rk3399-pinctrl";
>>   		rockchip,grf = <&grf>;
>
>
>




From ykk at rock-chips.com  Mon May 23 06:33:20 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Mon, 23 May 2016 21:33:20 +0800
Subject: [PATCH 0/3] Add the eDP/VOP device node for rk3399
Message-ID: <1464010400-10903-1-git-send-email-ykk@rock-chips.com>

This thread is rely on Mark's VOP thread[1] and Yakir's eDP thread[2].

[1]: https://lkml.org/lkml/2016/4/20/36
[2]: https://patchwork.freedesktop.org/patch/83406/


Mark Yao (1):
  arm64: dts: rockchip: add VOP and VOP iommu node for rk3399

Yakir Yang (2):
  arm64: dts: rockchip: add eDP device node for rk3399
  arm64: dts: rockchip: add backlight support for rk3399 evb board

 arch/arm64/boot/dts/rockchip/rk3399-evb.dts |  40 ++++++++++
 arch/arm64/boot/dts/rockchip/rk3399.dtsi    | 110 ++++++++++++++++++++++++++++
 2 files changed, 150 insertions(+)

-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 06:33:32 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Mon, 23 May 2016 21:33:32 +0800
Subject: [PATCH 1/3] arm64: dts: rockchip: add VOP and VOP iommu node for
 rk3399
In-Reply-To: <1464010400-10903-1-git-send-email-ykk@rock-chips.com>
References: <1464010400-10903-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464010412-10961-1-git-send-email-ykk@rock-chips.com>

From: Mark Yao <mark.yao at rock-chips.com>

Add the core display-subsystem node and the two display controllers
available on the rk3399.

Signed-off-by: Mark Yao <mark.yao at rock-chips.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 58 ++++++++++++++++++++++++++++++++
 1 file changed, 58 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a..54e5c25 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -543,6 +543,64 @@
 		status = "disabled";
 	};
 
+	vopl: vop at ff8f0000 {
+		compatible = "rockchip,rk3399-vop-lit";
+		reg = <0x0 0xff8f0000 0x0 0x3efc>;
+		interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP1>, <&cru DCLK_VOP1>, <&cru HCLK_VOP1>;
+		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
+		resets = <&cru SRST_A_VOP1>, <&cru SRST_H_VOP1>, <&cru SRST_D_VOP1>;
+		reset-names = "axi", "ahb", "dclk";
+		iommus = <&vopl_mmu>;
+		status = "disabled";
+
+		vopl_out: port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+
+	vopl_mmu: iommu at ff8f3f00 {
+		compatible = "rockchip,iommu";
+		reg = <0x0 0xff8f3f00 0x0 0x100>;
+		interrupts = <GIC_SPI 119 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "vopl_mmu";
+		#iommu-cells = <0>;
+		status = "disabled";
+	};
+
+	vopb: vop at ff900000 {
+		compatible = "rockchip,rk3399-vop-big";
+		reg = <0x0 0xff900000 0x0 0x3efc>;
+		interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru ACLK_VOP0>, <&cru DCLK_VOP0>, <&cru HCLK_VOP0>;
+		clock-names = "aclk_vop", "dclk_vop", "hclk_vop";
+		resets = <&cru SRST_A_VOP0>, <&cru SRST_H_VOP0>, <&cru SRST_D_VOP0>;
+		reset-names = "axi", "ahb", "dclk";
+		iommus = <&vopb_mmu>;
+		status = "disabled";
+
+		vopb_out: port {
+			#address-cells = <1>;
+			#size-cells = <0>;
+		};
+	};
+
+	vopb_mmu: iommu at ff903f00 {
+		compatible = "rockchip,iommu";
+		reg = <0x0 0xff903f00 0x0 0x100>;
+		interrupts = <GIC_SPI 118 IRQ_TYPE_LEVEL_HIGH>;
+		interrupt-names = "vopb_mmu";
+		#iommu-cells = <0>;
+		status = "disabled";
+	};
+
+	display_subsystem: display-subsystem {
+		compatible = "rockchip,display-subsystem";
+		ports = <&vopl_out>, <&vopb_out>;
+		status = "disabled";
+	};
+
 	pinctrl: pinctrl {
 		compatible = "rockchip,rk3399-pinctrl";
 		rockchip,grf = <&grf>;
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 06:33:38 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Mon, 23 May 2016 21:33:38 +0800
Subject: [PATCH 2/3] arm64: dts: rockchip: add eDP device node for rk3399
In-Reply-To: <1464010400-10903-1-git-send-email-ykk@rock-chips.com>
References: <1464010400-10903-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464010418-11014-1-git-send-email-ykk@rock-chips.com>

Add rk3399 eDP device node, and connect to VOP device node with
remote endpoint.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 52 ++++++++++++++++++++++++++++++++
 1 file changed, 52 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 54e5c25..be322db 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -557,6 +557,11 @@
 		vopl_out: port {
 			#address-cells = <1>;
 			#size-cells = <0>;
+
+			vopl_out_edp: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&edp_in_vopl>;
+			};
 		};
 	};
 
@@ -583,6 +588,11 @@
 		vopb_out: port {
 			#address-cells = <1>;
 			#size-cells = <0>;
+
+			vopb_out_edp: endpoint at 0 {
+				reg = <0>;
+				remote-endpoint = <&edp_in_vopb>;
+			};
 		};
 	};
 
@@ -595,6 +605,41 @@
 		status = "disabled";
 	};
 
+	edp: edp at ff970000 {
+		compatible = "rockchip,rk3399-edp";
+		reg = <0x0 0xff970000 0x0 0x8000>;
+		interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru PCLK_EDP>, <&cru PCLK_EDP_CTRL>;
+		clock-names = "dp", "pclk";
+		resets = <&cru SRST_P_EDP_CTRL>;
+		reset-names = "dp";
+		rockchip,grf = <&grf>;
+		status = "disabled";
+		pinctrl-names = "default";
+		pinctrl-0 = <&edp_hpd>;
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+
+			edp_in: port at 0 {
+				reg = <0>;
+				#address-cells = <1>;
+				#size-cells = <0>;
+
+				edp_in_vopb: endpoint at 0 {
+					reg = <0>;
+					remote-endpoint = <&vopb_out_edp>;
+				};
+
+				edp_in_vopl: endpoint at 1 {
+					reg = <1>;
+					remote-endpoint = <&vopl_out_edp>;
+				};
+			};
+		};
+	};
+
 	display_subsystem: display-subsystem {
 		compatible = "rockchip,display-subsystem";
 		ports = <&vopl_out>, <&vopb_out>;
@@ -1067,5 +1112,12 @@
 					<1 14 RK_FUNC_1 &pcfg_pull_none>;
 			};
 		};
+
+		edp {
+			edp_hpd: edp-hpd {
+				rockchip,pins =
+					<4 23 RK_FUNC_2 &pcfg_pull_none>;
+			};
+		};
 	};
 };
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 06:33:42 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Mon, 23 May 2016 21:33:42 +0800
Subject: [PATCH 3/3] arm64: dts: rockchip: add backlight support for rk3399
 evb board
In-Reply-To: <1464010400-10903-1-git-send-email-ykk@rock-chips.com>
References: <1464010400-10903-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464010422-11067-1-git-send-email-ykk@rock-chips.com>

Add backlight node for evb board, perpare for panel device node.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 arch/arm64/boot/dts/rockchip/rk3399-evb.dts | 40 +++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
index 1a3eb14..31d9e27 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
+++ b/arch/arm64/boot/dts/rockchip/rk3399-evb.dts
@@ -75,6 +75,46 @@
 		regulator-always-on;
 		regulator-boot-on;
 	};
+
+	backlight: backlight {
+		compatible = "pwm-backlight";
+		pwms = <&pwm0 0 25000 0>;
+		brightness-levels = <
+			  0   1   2   3   4   5   6   7
+			  8   9  10  11  12  13  14  15
+			 16  17  18  19  20  21  22  23
+			 24  25  26  27  28  29  30  31
+			 32  33  34  35  36  37  38  39
+			 40  41  42  43  44  45  46  47
+			 48  49  50  51  52  53  54  55
+			 56  57  58  59  60  61  62  63
+			 64  65  66  67  68  69  70  71
+			 72  73  74  75  76  77  78  79
+			 80  81  82  83  84  85  86  87
+			 88  89  90  91  92  93  94  95
+			 96  97  98  99 100 101 102 103
+			104 105 106 107 108 109 110 111
+			112 113 114 115 116 117 118 119
+			120 121 122 123 124 125 126 127
+			128 129 130 131 132 133 134 135
+			136 137 138 139 140 141 142 143
+			144 145 146 147 148 149 150 151
+			152 153 154 155 156 157 158 159
+			160 161 162 163 164 165 166 167
+			168 169 170 171 172 173 174 175
+			176 177 178 179 180 181 182 183
+			184 185 186 187 188 189 190 191
+			192 193 194 195 196 197 198 199
+			200 201 202 203 204 205 206 207
+			208 209 210 211 212 213 214 215
+			216 217 218 219 220 221 222 223
+			224 225 226 227 228 229 230 231
+			232 233 234 235 236 237 238 239
+			240 241 242 243 244 245 246 247
+			248 249 250 251 252 253 254 255>;
+		default-brightness-level = <200>;
+		enable-gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
+	};
 };
 
 &pwm0 {
-- 
1.9.1




From catalin.marinas at arm.com  Mon May 23 06:35:00 2016
From: catalin.marinas at arm.com (Catalin Marinas)
Date: Mon, 23 May 2016 14:35:00 +0100
Subject: [PATCH 4/5] iommu/rockchip: add ARM64 cache flush operation for
 iommu
In-Reply-To: <5742DEFE.1040902@arm.com>
References: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
 <1463967439-13354-5-git-send-email-zhengsq@rock-chips.com>
 <5742DEFE.1040902@arm.com>
Message-ID: <20160523133500.GF4892@e104818-lin.cambridge.arm.com>

On Mon, May 23, 2016 at 11:44:14AM +0100, Robin Murphy wrote:
> On 23/05/16 02:37, Shunqian Zheng wrote:
> >From: Simon <xxm at rock-chips.com>
> >
> >Signed-off-by: Simon <xxm at rock-chips.com>
> >---
> >  drivers/iommu/rockchip-iommu.c | 4 ++++
> >  1 file changed, 4 insertions(+)
> >
> >diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> >index 043d18c..1741b65 100644
> >--- a/drivers/iommu/rockchip-iommu.c
> >+++ b/drivers/iommu/rockchip-iommu.c
> >@@ -95,12 +95,16 @@ struct rk_iommu {
> >
> >  static inline void rk_table_flush(u32 *va, unsigned int count)
> >  {
> >+#if defined(CONFIG_ARM)
> >  	phys_addr_t pa_start = virt_to_phys(va);
> >  	phys_addr_t pa_end = virt_to_phys(va + count);
> >  	size_t size = pa_end - pa_start;
> >
> >  	__cpuc_flush_dcache_area(va, size);
> >  	outer_flush_range(pa_start, pa_end);
> >+#elif defined(CONFIG_ARM64)
> >+	__dma_flush_range(va, va + count);
> >+#endif
> 
> Ugh, please don't use arch-private cache maintenance functions directly from
> a driver. Allocating/mapping page tables to be read by the IOMMU is still
> DMA, so using the DMA APIs is the correct way to manage them, *especially*
> if it needs to work across multiple architectures.

I fully agree, these functions should not be used in drivers.

-- 
Catalin


From zhengxing at rock-chips.com  Mon May 23 07:43:32 2016
From: zhengxing at rock-chips.com (Xing Zheng)
Date: Mon, 23 May 2016 22:43:32 +0800
Subject: [PATCH v2] ASoC: rockchip: Add machine driver for
 MAX98357A/RT5514/DA7219
Message-ID: <1464014612-14396-1-git-send-email-zhengxing@rock-chips.com>

There are multi codec devices on the RK3399 platform, we can use
this patch support and control these codecs.

---

Changes in v2:
Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>

 .../sound/rockchip-max98357a-rt5514-da7219.txt     |   15 +
 sound/soc/rockchip/Kconfig                         |   11 +
 sound/soc/rockchip/Makefile                        |    2 +
 .../rockchip/rockchip_max98357a_rt5514_da7219.c    |  333 ++++++++++++++++++++
 4 files changed, 361 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
 create mode 100644 sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c

diff --git a/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
new file mode 100644
index 0000000..5928384
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
@@ -0,0 +1,15 @@
+ROCKCHIP with MAX98357A/RT5514/DA7219 codecs
+
+Required properties:
+- compatible: "rockchip,rockchip-sound"
+- rockchip,cpu: The phandle of the Rockchip I2S controller that's
+  connected to the codecs
+- rockchip,codec: The phandle of the MAX98357A/RT5514/DA7219 codecs
+
+Example:
+
+sound {
+	compatible = "rockchip,rockchip-sound";
+	rockchip,cpu = <&i2s0 &i2s0 &i2s1>;
+	rockchip,codec = <&max98357a &headsetcodec &codec>;
+};
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index f1e0c70..d02aa94 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -41,3 +41,14 @@ config SND_SOC_ROCKCHIP_RT5645
 	help
 	  Say Y or M here if you want to add support for SoC audio on Rockchip
 	  boards using the RT5645/RT5650 codec, such as Veyron.
+
+config SND_SOC_ROCKCHIP_MAX98357A_RT5514_DA7219
+	tristate "ASoC support for Rockchip boards using the MAX98357A/RT5514/DA7219"
+	depends on SND_SOC_ROCKCHIP && GPIOLIB
+	select SND_SOC_ROCKCHIP_I2S
+	select SND_SOC_MAX98357A
+	select SND_SOC_RT5514
+	select SND_SOC_DA7219
+	help
+	  Say Y or M here if you want to add support for SoC audio on Rockchip
+	  boards using the MAX98357A/RT5514/DA7219.
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index c0bf560..ca97489 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
 
 snd-soc-rockchip-max98090-objs := rockchip_max98090.o
 snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
+snd-soc-rockchip-max98357a-rt5514-da7219-objs := rockchip_max98357a_rt5514_da7219.o
 
 obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
+obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98357A_RT5514_DA7219) += snd-soc-rockchip-max98357a-rt5514-da7219.o
diff --git a/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c b/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c
new file mode 100644
index 0000000..818c47e
--- /dev/null
+++ b/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c
@@ -0,0 +1,333 @@
+/*
+ * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
+ *
+ * Copyright (c) 2016, ROCKCHIP CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "rockchip_i2s.h"
+#include "../codecs/da7219.h"
+#include "../codecs/da7219-aad.h"
+#include "../codecs/rt5514.h"
+
+#define DRV_NAME "rockchip-sound"
+
+#define SOUND_FS	256
+
+static struct snd_soc_jack rockchip_sound_jack;
+
+static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphones", NULL),
+	SND_SOC_DAPM_SPK("Speakers", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route rockchip_dapm_routes[] = {
+	/* Input Lines */
+	{"MIC", NULL, "Headset Mic"},
+	{"DMIC1L", NULL, "Int Mic"},
+	{"DMIC1R", NULL, "Int Mic"},
+
+	/* Output Lines */
+	{"Headphones", NULL, "HPL"},
+	{"Headphones", NULL, "HPR"},
+	{"Speakers", NULL, "Speakers"},
+};
+
+static const struct snd_kcontrol_new rockchip_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphones"),
+	SOC_DAPM_PIN_SWITCH("Speakers"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Int Mic"),
+};
+
+static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+	unsigned int mclk;
+	int ret;
+
+	/* max98357a supports these sample rates */
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		mclk = params_rate(params) * SOUND_FS;
+		break;
+	default:
+		dev_err(rtd->card->dev, "%s() doesn't support this sample rate: %d\n",
+				__func__, params_rate(params));
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
+	if (ret) {
+		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
+				__func__, mclk, ret);
+		return ret;
+	}
+
+	snd_soc_dapm_disable_pin(dapm, "Headphones");
+	snd_soc_dapm_enable_pin(dapm, "Speakers");
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	unsigned int mclk;
+	int ret;
+
+	mclk = params_rate(params) * SOUND_FS;
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+				     SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,
+				     mclk, SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
+				__func__, params_rate(params) * 512, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+	int mclk, ret;
+
+	/* in bypass mode, the mclk has to be one of the frequencies below */
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 24000:
+	case 32000:
+	case 48000:
+	case 64000:
+	case 96000:
+		mclk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+	case 88200:
+		mclk = 11289600;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+				     SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);
+		return ret;
+	}
+
+	snd_soc_dapm_disable_pin(dapm, "Speakers");
+	snd_soc_dapm_enable_pin(dapm, "Headphones");
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec_dais[0]->codec;
+	int ret;
+
+	/* Enable Headset and 4 Buttons Jack detection */
+	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+				    SND_JACK_HEADSET |
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
+				    &rockchip_sound_jack, NULL, 0);
+
+	if (ret) {
+		dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);
+		return ret;
+	}
+
+	da7219_aad_jack_det(codec, &rockchip_sound_jack);
+
+	return 0;
+}
+
+static struct snd_soc_ops rockchip_sound_max98357a_ops = {
+	.hw_params = rockchip_sound_max98357a_hw_params,
+};
+
+static struct snd_soc_ops rockchip_sound_rt5514_ops = {
+	.hw_params = rockchip_sound_rt5514_hw_params,
+};
+
+static struct snd_soc_ops rockchip_sound_da7219_ops = {
+	.hw_params = rockchip_sound_da7219_hw_params,
+};
+
+enum {
+	DAILINK_MAX98357A,
+	DAILINK_RT5514,
+	DAILINK_DA7219,
+};
+
+static struct snd_soc_dai_link rockchip_dailinks[] = {
+	[DAILINK_MAX98357A] = {
+		.name = "MAX98357A",
+		.stream_name = "MAX98357A PCM",
+		.codec_dai_name = "HiFi",
+		.ops = &rockchip_sound_max98357a_ops,
+		/* set max98357a as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+	[DAILINK_RT5514] = {
+		.name = "RT5514",
+		.stream_name = "RT5514 PCM",
+		.codec_dai_name = "rt5514-aif1",
+		.ops = &rockchip_sound_rt5514_ops,
+		/* set rt5514 as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+	[DAILINK_DA7219] = {
+		.name = "DA7219",
+		.stream_name = "DA7219 PCM",
+		.codec_dai_name = "da7219-hifi",
+		.init = rockchip_sound_da7219_init,
+		.ops = &rockchip_sound_da7219_ops,
+		/* set da7219 as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+};
+
+static struct snd_soc_card rockchip_sound_card = {
+	.name = "rockchip-sound",
+	.owner = THIS_MODULE,
+	.dai_link = rockchip_dailinks,
+	.num_links =  ARRAY_SIZE(rockchip_dailinks),
+	.dapm_widgets = rockchip_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
+	.dapm_routes = rockchip_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
+	.controls = rockchip_controls,
+	.num_controls = ARRAY_SIZE(rockchip_controls),
+};
+
+static int rockchip_sound_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &rockchip_sound_card;
+	struct device_node *cpu_node;
+	int i, ret;
+
+	for (i = 0; i < card->num_links; i++) {
+		cpu_node = of_parse_phandle(pdev->dev.of_node,
+					 "rockchip,cpu", i);
+		if (!cpu_node) {
+			dev_err(&pdev->dev, "Property[%d] 'rockchip,cpu' missing or invalid\n", i);
+			return -EINVAL;
+		}
+
+		rockchip_dailinks[i].platform_of_node = cpu_node;
+		rockchip_dailinks[i].cpu_of_node = cpu_node;
+
+		rockchip_dailinks[i].codec_of_node =
+			of_parse_phandle(pdev->dev.of_node, "rockchip,codec", i);
+		if (!rockchip_dailinks[i].codec_of_node) {
+			dev_err(&pdev->dev,
+				"Property[%d] 'rockchip,codec' missing or invalid\n", i);
+			return -EINVAL;
+		}
+	}
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static const struct of_device_id rockchip_sound_of_match[] = {
+	{ .compatible = "rockchip,rockchip-sound", },
+	{},
+};
+
+static struct platform_driver rockchip_sound_driver = {
+	.probe = rockchip_sound_probe,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = rockchip_sound_of_match,
+#ifdef CONFIG_PM
+		.pm = &snd_soc_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(rockchip_sound_driver);
+
+MODULE_AUTHOR("Xing Zheng <zhengxing at rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);
-- 
1.7.9.5




From heiko at sntech.de  Mon May 23 07:51:08 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 23 May 2016 16:51:08 +0200
Subject: [PATCH v2] ASoC: rockchip: Add machine driver for
 MAX98357A/RT5514/DA7219
In-Reply-To: <1464014612-14396-1-git-send-email-zhengxing@rock-chips.com>
References: <1464014612-14396-1-git-send-email-zhengxing@rock-chips.com>
Message-ID: <6209835.s95gRr0Nsp@phil>

Hi Xing,

Am Montag, 23. Mai 2016, 22:43:32 schrieb Xing Zheng:
> There are multi codec devices on the RK3399 platform, we can use
> this patch support and control these codecs.
> 
> ---
> 
> Changes in v2:
> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>

something seems to have gone wrong here.

The Signed-off needs to be above the "---" and the changelog itself seems 
empty while at least the number of lines in your 
rockchip_max98357a_rt5514_da7219.c seems to have changed.

> 
>  .../sound/rockchip-max98357a-rt5514-da7219.txt     |   15 +
>  sound/soc/rockchip/Kconfig                         |   11 +
>  sound/soc/rockchip/Makefile                        |    2 +
>  .../rockchip/rockchip_max98357a_rt5514_da7219.c    |  333
> ++++++++++++++++++++ 4 files changed, 361 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.
> txt create mode 100644
> sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c
> 
> diff --git
> a/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da721
> 9.txt
> b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da721
> 9.txt new file mode 100644
> index 0000000..5928384
> --- /dev/null
> +++
> b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da721
> 9.txt @@ -0,0 +1,15 @@
> +ROCKCHIP with MAX98357A/RT5514/DA7219 codecs
> +
> +Required properties:
> +- compatible: "rockchip,rockchip-sound"
> +- rockchip,cpu: The phandle of the Rockchip I2S controller that's
> +  connected to the codecs
> +- rockchip,codec: The phandle of the MAX98357A/RT5514/DA7219 codecs
> +
> +Example:
> +
> +sound {
> +	compatible = "rockchip,rockchip-sound";
> +	rockchip,cpu = <&i2s0 &i2s0 &i2s1>;
> +	rockchip,codec = <&max98357a &headsetcodec &codec>;
> +};
> diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
> index f1e0c70..d02aa94 100644
> --- a/sound/soc/rockchip/Kconfig
> +++ b/sound/soc/rockchip/Kconfig
> @@ -41,3 +41,14 @@ config SND_SOC_ROCKCHIP_RT5645
>  	help
>  	  Say Y or M here if you want to add support for SoC audio on Rockchip
>  	  boards using the RT5645/RT5650 codec, such as Veyron.
> +
> +config SND_SOC_ROCKCHIP_MAX98357A_RT5514_DA7219
> +	tristate "ASoC support for Rockchip boards using the
> MAX98357A/RT5514/DA7219" +	depends on SND_SOC_ROCKCHIP && GPIOLIB
> +	select SND_SOC_ROCKCHIP_I2S
> +	select SND_SOC_MAX98357A
> +	select SND_SOC_RT5514
> +	select SND_SOC_DA7219
> +	help
> +	  Say Y or M here if you want to add support for SoC audio on Rockchip
> +	  boards using the MAX98357A/RT5514/DA7219.
> diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
> index c0bf560..ca97489 100644
> --- a/sound/soc/rockchip/Makefile
> +++ b/sound/soc/rockchip/Makefile
> @@ -7,6 +7,8 @@ obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) +=
> snd-soc-rockchip-spdif.o
> 
>  snd-soc-rockchip-max98090-objs := rockchip_max98090.o
>  snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
> +snd-soc-rockchip-max98357a-rt5514-da7219-objs :=
> rockchip_max98357a_rt5514_da7219.o
> 
>  obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
>  obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
> +obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98357A_RT5514_DA7219) +=
> snd-soc-rockchip-max98357a-rt5514-da7219.o diff --git
> a/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c
> b/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c new file mode
> 100644
> index 0000000..818c47e
> --- /dev/null
> +++ b/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c
> @@ -0,0 +1,333 @@
> +/*
> + * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
> + *
> + * Copyright (c) 2016, ROCKCHIP CORPORATION.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify
> it + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
> for + * more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +
> +#include <linux/module.h>
> +#include <linux/platform_device.h>
> +#include <linux/slab.h>
> +#include <linux/gpio.h>
> +#include <linux/of_gpio.h>
> +#include <linux/delay.h>
> +#include <linux/spi/spi.h>
> +#include <sound/core.h>
> +#include <sound/jack.h>
> +#include <sound/pcm.h>
> +#include <sound/pcm_params.h>
> +#include <sound/soc.h>
> +#include "rockchip_i2s.h"
> +#include "../codecs/da7219.h"
> +#include "../codecs/da7219-aad.h"
> +#include "../codecs/rt5514.h"
> +
> +#define DRV_NAME "rockchip-sound"
> +
> +#define SOUND_FS	256
> +
> +static struct snd_soc_jack rockchip_sound_jack;
> +
> +static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
> +	SND_SOC_DAPM_HP("Headphones", NULL),
> +	SND_SOC_DAPM_SPK("Speakers", NULL),
> +	SND_SOC_DAPM_MIC("Headset Mic", NULL),
> +	SND_SOC_DAPM_MIC("Int Mic", NULL),
> +};
> +
> +static const struct snd_soc_dapm_route rockchip_dapm_routes[] = {
> +	/* Input Lines */
> +	{"MIC", NULL, "Headset Mic"},
> +	{"DMIC1L", NULL, "Int Mic"},
> +	{"DMIC1R", NULL, "Int Mic"},
> +
> +	/* Output Lines */
> +	{"Headphones", NULL, "HPL"},
> +	{"Headphones", NULL, "HPR"},
> +	{"Speakers", NULL, "Speakers"},
> +};
> +
> +static const struct snd_kcontrol_new rockchip_controls[] = {
> +	SOC_DAPM_PIN_SWITCH("Headphones"),
> +	SOC_DAPM_PIN_SWITCH("Speakers"),
> +	SOC_DAPM_PIN_SWITCH("Headset Mic"),
> +	SOC_DAPM_PIN_SWITCH("Int Mic"),
> +};
> +
> +static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream
> *substream, +			     struct snd_pcm_hw_params *params)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
> +	unsigned int mclk;
> +	int ret;
> +
> +	/* max98357a supports these sample rates */
> +	switch (params_rate(params)) {
> +	case 8000:
> +	case 16000:
> +	case 48000:
> +	case 96000:
> +		mclk = params_rate(params) * SOUND_FS;
> +		break;
> +	default:
> +		dev_err(rtd->card->dev, "%s() doesn't support this sample rate: 
%d\n",
> +				__func__, params_rate(params));
> +		return -EINVAL;
> +	}
> +
> +	ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
> +	if (ret) {
> +		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
> +				__func__, mclk, ret);
> +		return ret;
> +	}
> +
> +	snd_soc_dapm_disable_pin(dapm, "Headphones");
> +	snd_soc_dapm_enable_pin(dapm, "Speakers");
> +	snd_soc_dapm_sync(dapm);
> +
> +	return 0;
> +}
> +
> +static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream
> *substream, +			     struct snd_pcm_hw_params *params)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
> +	struct snd_soc_dai *codec_dai = rtd->codec_dai;
> +	unsigned int mclk;
> +	int ret;
> +
> +	mclk = params_rate(params) * SOUND_FS;
> +
> +	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
> +				     SND_SOC_CLOCK_OUT);
> +	if (ret < 0) {
> +		dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,
> +				     mclk, SND_SOC_CLOCK_IN);
> +	if (ret) {
> +		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
> +				__func__, params_rate(params) * 512, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream
> *substream, +			     struct snd_pcm_hw_params *params)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
> +	struct snd_soc_dai *codec_dai = rtd->codec_dai;
> +	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
> +	int mclk, ret;
> +
> +	/* in bypass mode, the mclk has to be one of the frequencies below */
> +	switch (params_rate(params)) {
> +	case 8000:
> +	case 16000:
> +	case 24000:
> +	case 32000:
> +	case 48000:
> +	case 64000:
> +	case 96000:
> +		mclk = 12288000;
> +		break;
> +	case 11025:
> +	case 22050:
> +	case 44100:
> +	case 88200:
> +		mclk = 11289600;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
> +				     SND_SOC_CLOCK_OUT);
> +	if (ret < 0) {
> +		dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
> +				     SND_SOC_CLOCK_IN);
> +	if (ret < 0) {
> +		dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
> +	if (ret < 0) {
> +		dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);
> +		return ret;
> +	}
> +
> +	snd_soc_dapm_disable_pin(dapm, "Speakers");
> +	snd_soc_dapm_enable_pin(dapm, "Headphones");
> +	snd_soc_dapm_sync(dapm);
> +
> +	return 0;
> +}
> +
> +static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
> +{
> +	struct snd_soc_codec *codec = rtd->codec_dais[0]->codec;
> +	int ret;
> +
> +	/* Enable Headset and 4 Buttons Jack detection */
> +	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
> +				    SND_JACK_HEADSET |
> +				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
> +				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
> +				    &rockchip_sound_jack, NULL, 0);
> +
> +	if (ret) {
> +		dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);
> +		return ret;
> +	}
> +
> +	da7219_aad_jack_det(codec, &rockchip_sound_jack);
> +
> +	return 0;
> +}
> +
> +static struct snd_soc_ops rockchip_sound_max98357a_ops = {
> +	.hw_params = rockchip_sound_max98357a_hw_params,
> +};
> +
> +static struct snd_soc_ops rockchip_sound_rt5514_ops = {
> +	.hw_params = rockchip_sound_rt5514_hw_params,
> +};
> +
> +static struct snd_soc_ops rockchip_sound_da7219_ops = {
> +	.hw_params = rockchip_sound_da7219_hw_params,
> +};
> +
> +enum {
> +	DAILINK_MAX98357A,
> +	DAILINK_RT5514,
> +	DAILINK_DA7219,
> +};
> +
> +static struct snd_soc_dai_link rockchip_dailinks[] = {
> +	[DAILINK_MAX98357A] = {
> +		.name = "MAX98357A",
> +		.stream_name = "MAX98357A PCM",
> +		.codec_dai_name = "HiFi",
> +		.ops = &rockchip_sound_max98357a_ops,
> +		/* set max98357a as slave */
> +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
> +			SND_SOC_DAIFMT_CBS_CFS,
> +	},
> +	[DAILINK_RT5514] = {
> +		.name = "RT5514",
> +		.stream_name = "RT5514 PCM",
> +		.codec_dai_name = "rt5514-aif1",
> +		.ops = &rockchip_sound_rt5514_ops,
> +		/* set rt5514 as slave */
> +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
> +			SND_SOC_DAIFMT_CBS_CFS,
> +	},
> +	[DAILINK_DA7219] = {
> +		.name = "DA7219",
> +		.stream_name = "DA7219 PCM",
> +		.codec_dai_name = "da7219-hifi",
> +		.init = rockchip_sound_da7219_init,
> +		.ops = &rockchip_sound_da7219_ops,
> +		/* set da7219 as slave */
> +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
> +			SND_SOC_DAIFMT_CBS_CFS,
> +	},
> +};
> +
> +static struct snd_soc_card rockchip_sound_card = {
> +	.name = "rockchip-sound",
> +	.owner = THIS_MODULE,
> +	.dai_link = rockchip_dailinks,
> +	.num_links =  ARRAY_SIZE(rockchip_dailinks),
> +	.dapm_widgets = rockchip_dapm_widgets,
> +	.num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
> +	.dapm_routes = rockchip_dapm_routes,
> +	.num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
> +	.controls = rockchip_controls,
> +	.num_controls = ARRAY_SIZE(rockchip_controls),
> +};
> +
> +static int rockchip_sound_probe(struct platform_device *pdev)
> +{
> +	struct snd_soc_card *card = &rockchip_sound_card;
> +	struct device_node *cpu_node;
> +	int i, ret;
> +
> +	for (i = 0; i < card->num_links; i++) {
> +		cpu_node = of_parse_phandle(pdev->dev.of_node,
> +					 "rockchip,cpu", i);
> +		if (!cpu_node) {
> +			dev_err(&pdev->dev, "Property[%d] 'rockchip,cpu' missing or
> invalid\n", i); +			return -EINVAL;
> +		}
> +
> +		rockchip_dailinks[i].platform_of_node = cpu_node;
> +		rockchip_dailinks[i].cpu_of_node = cpu_node;
> +
> +		rockchip_dailinks[i].codec_of_node =
> +			of_parse_phandle(pdev->dev.of_node, "rockchip,codec", i);
> +		if (!rockchip_dailinks[i].codec_of_node) {
> +			dev_err(&pdev->dev,
> +				"Property[%d] 'rockchip,codec' missing or invalid\n", i);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	card->dev = &pdev->dev;
> +	platform_set_drvdata(pdev, card);
> +
> +	ret = devm_snd_soc_register_card(&pdev->dev, card);
> +	if (ret)
> +		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
> +			__func__, ret);
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id rockchip_sound_of_match[] = {
> +	{ .compatible = "rockchip,rockchip-sound", },
> +	{},
> +};
> +
> +static struct platform_driver rockchip_sound_driver = {
> +	.probe = rockchip_sound_probe,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.of_match_table = rockchip_sound_of_match,
> +#ifdef CONFIG_PM
> +		.pm = &snd_soc_pm_ops,
> +#endif
> +	},
> +};
> +
> +module_platform_driver(rockchip_sound_driver);
> +
> +MODULE_AUTHOR("Xing Zheng <zhengxing at rock-chips.com>");
> +MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:" DRV_NAME);
> +MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);



From heiko at sntech.de  Mon May 23 07:58:56 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 23 May 2016 16:58:56 +0200
Subject: [PATCH 0/3] Rockchip: generalize GRF setup
Message-ID: <1464015539-19521-1-git-send-email-heiko@sntech.de>

The General register files contain a big bunch of settings for various
components. Things like the automatic sdmmc/jtag switch may even affect
us in a bad way, while that property (and possibly others) are not even
part of the dw_mmc controller itself.

And while the rk3288 could still carry adaptions to these defaults
in its mach files, this is no longer possible on the arm64 socs, while
things like the jtag-switch from above still can affect us there.

So introduce a separate driver that binds to the already set soc-
specific grf compatibles and does the necessary setup for things.

It could also take over handling the grf pclk so that we don't have
to have the clock-framework keep control of it, as disabling causes
havok on the system.


Heiko Stuebner (3):
  dt-bindings: add used but undocumented rockchip grf compatible values
  soc: rockchip: add driver handling grf setup
  ARM: rockchip: drop jtag/mmc switch handling

 .../devicetree/bindings/soc/rockchip/grf.txt       |   4 +
 arch/arm/mach-rockchip/rockchip.c                  |  12 --
 drivers/soc/rockchip/Kconfig                       |  10 ++
 drivers/soc/rockchip/Makefile                      |   1 +
 drivers/soc/rockchip/grf.c                         | 138 +++++++++++++++++++++
 5 files changed, 153 insertions(+), 12 deletions(-)
 create mode 100644 drivers/soc/rockchip/grf.c

-- 
2.6.4



From heiko at sntech.de  Mon May 23 07:58:59 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 23 May 2016 16:58:59 +0200
Subject: [PATCH 3/3] ARM: rockchip: drop rk3288 jtag/mmc switch handling
In-Reply-To: <1464015539-19521-1-git-send-email-heiko@sntech.de>
References: <1464015539-19521-1-git-send-email-heiko@sntech.de>
Message-ID: <1464015539-19521-4-git-send-email-heiko@sntech.de>

We moved that functionality to a more generic place where it can also
be used for other socs, so drop it from architecture code.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
 arch/arm/mach-rockchip/rockchip.c | 12 ------------
 1 file changed, 12 deletions(-)

diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
index beb71da..e7b2aa7 100644
--- a/arch/arm/mach-rockchip/rockchip.c
+++ b/arch/arm/mach-rockchip/rockchip.c
@@ -29,13 +29,11 @@
 #include "core.h"
 #include "pm.h"
 
-#define RK3288_GRF_SOC_CON0 0x244
 #define RK3288_TIMER6_7_PHYS 0xff810000
 
 static void __init rockchip_timer_init(void)
 {
 	if (of_machine_is_compatible("rockchip,rk3288")) {
-		struct regmap *grf;
 		void __iomem *reg_base;
 
 		/*
@@ -54,16 +52,6 @@ static void __init rockchip_timer_init(void)
 		} else {
 			pr_err("rockchip: could not map timer7 registers\n");
 		}
-
-		/*
-		 * Disable auto jtag/sdmmc switching that causes issues
-		 * with the mmc controllers making them unreliable
-		 */
-		grf = syscon_regmap_lookup_by_compatible("rockchip,rk3288-grf");
-		if (!IS_ERR(grf))
-			regmap_write(grf, RK3288_GRF_SOC_CON0, 0x10000000);
-		else
-			pr_err("rockchip: could not get grf syscon\n");
 	}
 
 	of_clk_init(NULL);
-- 
2.6.4



From heiko at sntech.de  Mon May 23 07:58:57 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 23 May 2016 16:58:57 +0200
Subject: [PATCH 1/3] dt-bindings: add used but undocumented rockchip grf
 compatible values
In-Reply-To: <1464015539-19521-1-git-send-email-heiko@sntech.de>
References: <1464015539-19521-1-git-send-email-heiko@sntech.de>
Message-ID: <1464015539-19521-2-git-send-email-heiko@sntech.de>

There are some more General Register Files used in devicetree files
already, but as of now undocumented in the binding document, fix that.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
 Documentation/devicetree/bindings/soc/rockchip/grf.txt | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.txt b/Documentation/devicetree/bindings/soc/rockchip/grf.txt
index 013e71a..c6e62cb 100644
--- a/Documentation/devicetree/bindings/soc/rockchip/grf.txt
+++ b/Documentation/devicetree/bindings/soc/rockchip/grf.txt
@@ -5,11 +5,13 @@ is composed of many registers for system control.
 
 From RK3368 SoCs, the GRF is divided into two sections,
 - GRF, used for general non-secure system,
+- SGRF, used for general secure system,
 - PMUGRF, used for always on system
 
 Required Properties:
 
 - compatible: GRF should be one of the followings
+   - "rockchip,rk3036-grf", "syscon": for rk3036
    - "rockchip,rk3066-grf", "syscon": for rk3066
    - "rockchip,rk3188-grf", "syscon": for rk3188
    - "rockchip,rk3228-grf", "syscon": for rk3228
@@ -19,6 +21,8 @@ Required Properties:
 - compatible: PMUGRF should be one of the followings
    - "rockchip,rk3368-pmugrf", "syscon": for rk3368
    - "rockchip,rk3399-pmugrf", "syscon": for rk3399
+- compatible: SGRF should be one of the following
+   - "rockchip,rk3288-sgrf", "syscon": for rk3288
 - reg: physical base address of the controller and length of memory mapped
   region.
 
-- 
2.6.4



From heiko at sntech.de  Mon May 23 07:58:58 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 23 May 2016 16:58:58 +0200
Subject: [PATCH 2/3] soc: rockchip: add driver handling grf setup
In-Reply-To: <1464015539-19521-1-git-send-email-heiko@sntech.de>
References: <1464015539-19521-1-git-send-email-heiko@sntech.de>
Message-ID: <1464015539-19521-3-git-send-email-heiko@sntech.de>

The General Register Files are an area of registers containing a lot
of single-bit settings for numerous components as well full components
like usbphy control. Therefore all used components are accessed
via the syscon provided by the grf nodes or from the sub-devices
created through the simple-mfd created from the grf node.

Some settings are not used by anything but will need to be set up
according to expectations on the kernel side.

Best example is the force_jtag setting, which defaults to on and
results in the soc switching the pin-outputs between jtag and sdmmc
automatically depending on the card-detect status. This conflicts
heavily with how the dw_mmc driver expects to do its work and also
with the clock-controller, which has most likely deactivated the
jtag clock due to it being unused.

So far the handling of this setting was living in the mach-rockchip
code for the arm32-based rk3288 but that of course doesn't work
for arm64 socs and would also look ugly for further arm32 socs.

So introduce a top-level driver for the grf that handles these
settings that need to be a certain way but nobody cares about.

Signed-off-by: Heiko Stuebner <heiko at sntech.de>
---
 drivers/soc/rockchip/Kconfig  |  10 +++
 drivers/soc/rockchip/Makefile |   1 +
 drivers/soc/rockchip/grf.c    | 138 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 149 insertions(+)
 create mode 100644 drivers/soc/rockchip/grf.c

diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig
index 7140ff8..20da55d 100644
--- a/drivers/soc/rockchip/Kconfig
+++ b/drivers/soc/rockchip/Kconfig
@@ -3,6 +3,16 @@ if ARCH_ROCKCHIP || COMPILE_TEST
 #
 # Rockchip Soc drivers
 #
+
+config ROCKCHIP_GRF
+	bool
+	default y
+	help
+	  The General Register Files are a central component providing
+	  special additional settings registers for a lot of soc-components.
+	  In a lot of cases there also need to be default settings initialized
+	  to make some of them conform to expectations of the kernel.
+
 config ROCKCHIP_PM_DOMAINS
         bool "Rockchip generic power domain"
         depends on PM
diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile
index 3d73d06..c851fa0 100644
--- a/drivers/soc/rockchip/Makefile
+++ b/drivers/soc/rockchip/Makefile
@@ -1,4 +1,5 @@
 #
 # Rockchip Soc drivers
 #
+obj-$(CONFIG_ROCKCHIP_GRF) += grf.o
 obj-$(CONFIG_ROCKCHIP_PM_DOMAINS) += pm_domains.o
diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c
new file mode 100644
index 0000000..25a1fd3
--- /dev/null
+++ b/drivers/soc/rockchip/grf.c
@@ -0,0 +1,138 @@
+/*
+ * Rockchip Generic Register Files setup
+ *
+ * Copyright (c) 2016 Heiko Stuebner <heiko at sntech.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/err.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define HIWORD_UPDATE(val, mask, shift) \
+		((val) << (shift) | (mask) << ((shift) + 16))
+
+struct rockchip_grf_value {
+	const char *desc;
+	u32 reg;
+	u32 val;
+};
+
+struct rockchip_grf_info {
+	const struct rockchip_grf_value *values;
+	int num_values;
+};
+
+#define RK3036_GRF_SOC_CON0		0x140
+
+static const struct rockchip_grf_value rk3036_defaults[] = {
+	/*
+	 * Disable auto jtag/sdmmc switching that causes issues with the
+	 * clock-framework and the mmc controllers making them unreliable.
+	 */
+	{ "jtag switching", RK3036_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 11) },
+};
+
+static const struct rockchip_grf_info rk3036_grf = {
+	.values = rk3036_defaults,
+	.num_values = ARRAY_SIZE(rk3036_defaults),
+};
+
+#define RK3288_GRF_SOC_CON0		0x244
+
+static const struct rockchip_grf_value rk3288_defaults[] = {
+	{ "jtag switching", RK3288_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 12) },
+};
+
+static const struct rockchip_grf_info rk3288_grf = {
+	.values = rk3288_defaults,
+	.num_values = ARRAY_SIZE(rk3288_defaults),
+};
+
+#define RK3399_GRF_SOC_CON7		0xe21c
+
+static const struct rockchip_grf_value rk3399_defaults[] = {
+	{ "jtag switching", RK3399_GRF_SOC_CON7, HIWORD_UPDATE(0, 1, 12) },
+
+};
+
+static const struct rockchip_grf_info rk3399_grf = {
+	.values = rk3399_defaults,
+	.num_values = ARRAY_SIZE(rk3399_defaults),
+};
+
+static const struct of_device_id rockchip_grf_dt_match[] = {
+	{
+		.compatible = "rockchip,rk3036-grf",
+		.data = (void *)&rk3036_grf,
+	}, {
+		.compatible = "rockchip,rk3288-grf",
+		.data = (void *)&rk3288_grf,
+	}, {
+		.compatible = "rockchip,rk3399-grf",
+		.data = (void *)&rk3399_grf,
+	},
+	{ /* sentinel */ },
+};
+
+static int rockchip_grf_probe(struct platform_device *pdev)
+{
+	const struct rockchip_grf_info *grf_info;
+	const struct of_device_id *match;
+	struct device *dev = &pdev->dev;
+	struct regmap *grf;
+	int i;
+
+	if (!dev->of_node)
+		return -ENODEV;
+
+	match = of_match_device(rockchip_grf_dt_match, dev);
+	if (!match || !match->data) {
+		dev_err(dev, "missing grf data\n");
+		return -EINVAL;
+	}
+
+	grf_info = match->data;
+
+	grf = syscon_node_to_regmap(dev->of_node);
+	if (IS_ERR(grf)) {
+		dev_err(dev, "rockchip: could not get grf syscon\n");
+		return PTR_ERR(grf);
+	}
+
+	for (i = 0; i < grf_info->num_values; i++) {
+		const struct rockchip_grf_value *val = &grf_info->values[i];
+
+		dev_dbg(dev, "adjusting %s in 0x%x to 0x%x\n",
+			val->desc, val->reg, val->val);
+		regmap_write(grf, val->reg, val->val);
+	}
+
+	return 0;
+}
+
+static struct platform_driver rockchip_grf_driver = {
+	.probe = rockchip_grf_probe,
+	.driver = {
+		.name   = "rockchip-grf",
+		.of_match_table = rockchip_grf_dt_match,
+		/*
+		 * The General Register Files are a central component
+		 * accessed by numerous ip blocks and we're setting
+		 * defaults which should only happen once.
+		 */
+		.suppress_bind_attrs = true,
+	},
+};
+
+static int __init rockchip_grf_drv_register(void)
+{
+	return platform_driver_register(&rockchip_grf_driver);
+}
+postcore_initcall(rockchip_grf_drv_register);
-- 
2.6.4



From bharat.kumar.gogada at xilinx.com  Mon May 23 08:15:20 2016
From: bharat.kumar.gogada at xilinx.com (Bharat Kumar Gogada)
Date: Mon, 23 May 2016 15:15:20 +0000
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <8520D5D51A55D047800579B094147198258ACE47@XAP-PVEXMBX01.xlnx.xilinx.com>

> +
> +	irq = platform_get_irq_byname(pdev, "pcie-sys");
> +	if (irq < 0) {
> +		dev_err(dev, "missing pcie_sys IRQ resource\n");
> +		return -EINVAL;
> +	}
> +	err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler,
> +			       IRQF_SHARED, "pcie-sys", port);
> +	if (err) {
> +		dev_err(dev, "failed to request pcie subsystem irq\n");
> +		return err;
> +	}
> +
> +	port->irq = platform_get_irq_byname(pdev, "pcie-legacy");
> +	if (port->irq < 0) {
> +		dev_err(dev, "missing pcie_legacy IRQ resource\n");
> +		return -EINVAL;
> +	}
> +	err = devm_request_irq(dev, port->irq,
> +			       rockchip_pcie_legacy_int_handler,
> +			       IRQF_SHARED,
> +			       "pcie-legacy",
> +			       port);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to request pcie-legacy irq\n");
> +		return err;
> +	}
> +
> +	irq = platform_get_irq_byname(pdev, "pcie-client");
> +	if (irq < 0) {
> +		dev_err(dev, "missing pcie-client IRQ resource\n");
> +		return -EINVAL;
> +	}
> +	err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler,
> +			       IRQF_SHARED, "pcie-client", port);
> +	if (err) {
> +		dev_err(dev, "failed to request pcie client irq\n");
> +		return err;
> +	}
> +

All of the above interrupt number details are being obtained from device tree, why not move above API's to rockchip_pcie_parse_dt.

> +	port->dev = dev;
> +	err = rockchip_pcie_parse_dt(port);
> +	if (err) {
> +		dev_err(dev, "Parsing DT failed\n");
> +		return err;
> +	}
> +
> +	pcie_write(port, 0x6040000, PCIE_RC_CONFIG_BASE + 0x8);
> +	pcie_write(port, 0x0, PCIE_CORE_CTRL_MGMT_BASE + 0x300);
> +
> +	pcie_write(port, (RC_REGION_0_ADDR_TRANS_L +
> RC_REGION_0_PASS_BITS),
> +		   PCIE_CORE_AXI_CONF_BASE);
> +	pcie_write(port, RC_REGION_0_ADDR_TRANS_H,
> +		   PCIE_CORE_AXI_CONF_BASE + 0x4);
> +	pcie_write(port, 0x0080000a, PCIE_CORE_AXI_CONF_BASE + 0x8);
> +	pcie_write(port, 0x00000000, PCIE_CORE_AXI_CONF_BASE + 0xc);

Why not move the above steps to rockchip_pcie_init_port function ? 
Please use macros instead of using values.


From heiko at sntech.de  Mon May 23 12:53:06 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Mon, 23 May 2016 21:53:06 +0200
Subject: [PATCH 1/2] Documentation: add binding description of Rockchip
 PCIe controller
In-Reply-To: <766c3fc9-7e92-6235-76d5-803cc116845a@rock-chips.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <3930626.4a3xBnzHhK@phil>
 <766c3fc9-7e92-6235-76d5-803cc116845a@rock-chips.com>
Message-ID: <35714508.Tep5CcJBvk@phil>

Am Samstag, 21. Mai 2016, 11:55:35 schrieb Shawn Lin:
> On 2016/5/20 19:20, Heiko Stuebner wrote:
> > Hi Shawn,
> > 
> > Am Freitag, 20. Mai 2016, 18:29:06 schrieb Shawn Lin:
> >> This patch add some required and optional properties for Rockchip
> >> PCIe controller. Also we add a example for how to use it.
> >> 
> >> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> >> 
> >> ---

[...]

> >> +- msi-parent: Link to the hardware entity that serves as the Message
> >> +- pinctrl-names : The pin control state names
> >> +- pinctrl-0: The "default" pinctrl state
> > 
> > I'm not sure if pinctrl-properties need to be described when you don't
> > need special handling in the form of additional pin states. The pcie
> > part does not do any pin-handling of its own.
> 
> We need it in prevention of any firmwares change the default state
> of #CLKREQ which is useful for ASPM. Also we have a backup pin for
> clkreqn called clkreqnb, which should be taken more consideration since
> when refering to any one of these two, pinctrl should configure the
> bit[14] of GRF_SOC_CON7 automatically. But it is unfortunately beyound
> the implementation of pinctrl-rk3399.
> 
> BTW, I don't know if we wanna support this action inside the pinctrl
> code?

The TRM says for me for that bit only "pcie_clkreq_sel port control" and 
that naming really suggests that it is a property of the pcie controller, 
not the generic pinctrl. So if this needs to be touched the pcie controller 
needs to do it.


> >> +- interrupt-map-mask and interrupt-map: standard PCI properties
> >> +- interrupt-controller: identifies the node as an interrupt controller
> >> +
> >> +Optional Property:
> >> +- ep-gpios: contain the entry for pre-reset gpio
> >> +- num-lanes: number of lanes to use
> >> +- assigned-clocks, assigned-clock-parents and assigned-clock-rates:
> >> standard +		   clock bindings. See ../clock/clock-bindings.txt
> > 
> > Again that (assigned-clocks handling) is not actual part of the pci-
> > controllers actions, but other parts and also described already
> > elsewhere.
> Basically it does. But this is an alternative choice for pcie-phy to
> generate the ref_clk. When we want 100MHz src clk for PLL inside the
> pcie-phy?we should add them, otherwise it's taken from xin 24MHz.
> 
> This is useful for SI testing or some others special cases. So should we
> add it as an option and leave a sample here?

What I meant was that while clock handling is important when looking at the 
whole system, the pcie controller itself does only care that it gets a 
clock, but not that much where you get it from.

So while assigned-clocks has its place in the real devicetree, I don't think 
it is an element of the actual pcie-controller binding.


Heiko


From dianders at chromium.org  Mon May 23 13:46:00 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 23 May 2016 13:46:00 -0700
Subject: [PATCH 2/3] soc: rockchip: add driver handling grf setup
In-Reply-To: <1464015539-19521-3-git-send-email-heiko@sntech.de>
References: <1464015539-19521-1-git-send-email-heiko@sntech.de>
 <1464015539-19521-3-git-send-email-heiko@sntech.de>
Message-ID: <CAD=FV=VbrhpyQ8Y+5qnYHmkSvq12im2tZtpgnryGeEdc7mci9g@mail.gmail.com>

Heiko,

On Mon, May 23, 2016 at 7:58 AM, Heiko Stuebner <heiko at sntech.de> wrote:
> +struct rockchip_grf_info {
> +       const struct rockchip_grf_value *values;
> +       int num_values;
> +};
> +
> +#define RK3036_GRF_SOC_CON0            0x140
> +
> +static const struct rockchip_grf_value rk3036_defaults[] = {

Worth saving the little bit of space by marking several of these
structures as __initconst ?


> +#define RK3399_GRF_SOC_CON7            0xe21c
> +
> +static const struct rockchip_grf_value rk3399_defaults[] = {
> +       { "jtag switching", RK3399_GRF_SOC_CON7, HIWORD_UPDATE(0, 1, 12) },
> +
> +};

nit: extra blank line in rk3399_defaults?


> +static int rockchip_grf_probe(struct platform_device *pdev)
> +{
> +       const struct rockchip_grf_info *grf_info;
> +       const struct of_device_id *match;
> +       struct device *dev = &pdev->dev;
> +       struct regmap *grf;
> +       int i;
> +
> +       if (!dev->of_node)
> +               return -ENODEV;
> +
> +       match = of_match_device(rockchip_grf_dt_match, dev);
> +       if (!match || !match->data) {
> +               dev_err(dev, "missing grf data\n");
> +               return -EINVAL;
> +       }
> +
> +       grf_info = match->data;
> +
> +       grf = syscon_node_to_regmap(dev->of_node);
> +       if (IS_ERR(grf)) {
> +               dev_err(dev, "rockchip: could not get grf syscon\n");
> +               return PTR_ERR(grf);
> +       }
> +
> +       for (i = 0; i < grf_info->num_values; i++) {
> +               const struct rockchip_grf_value *val = &grf_info->values[i];
> +
> +               dev_dbg(dev, "adjusting %s in 0x%x to 0x%x\n",

optional-nitty-nit saves a character: s/0x%x/%#x/

...or even force to 4 hex digits: %#6x

> +                       val->desc, val->reg, val->val);
> +               regmap_write(grf, val->reg, val->val);

Dunno if we care, but regmap_write() does return an error.  Presumably
it might return an error here if you somehow specified an offset that
was outside of the range for the GRF?


-Doug


From dianders at chromium.org  Mon May 23 13:47:20 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 23 May 2016 13:47:20 -0700
Subject: [PATCH 3/3] ARM: rockchip: drop rk3288 jtag/mmc switch handling
In-Reply-To: <1464015539-19521-4-git-send-email-heiko@sntech.de>
References: <1464015539-19521-1-git-send-email-heiko@sntech.de>
 <1464015539-19521-4-git-send-email-heiko@sntech.de>
Message-ID: <CAD=FV=UC1uL9SeF5ZWKBO+b1AJJLCB91nTt1bi92ysEt9Nhekw@mail.gmail.com>

Heiko,

On Mon, May 23, 2016 at 7:58 AM, Heiko Stuebner <heiko at sntech.de> wrote:
> We moved that functionality to a more generic place where it can also
> be used for other socs, so drop it from architecture code.
>
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> ---
>  arch/arm/mach-rockchip/rockchip.c | 12 ------------
>  1 file changed, 12 deletions(-)

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Mon May 23 13:47:26 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 23 May 2016 13:47:26 -0700
Subject: [PATCH 1/3] dt-bindings: add used but undocumented rockchip grf
 compatible values
In-Reply-To: <1464015539-19521-2-git-send-email-heiko@sntech.de>
References: <1464015539-19521-1-git-send-email-heiko@sntech.de>
 <1464015539-19521-2-git-send-email-heiko@sntech.de>
Message-ID: <CAD=FV=Vss6kx1Rpmi5iYGCfNBfRPU3pX4-2SysjSmhwVM_uGyA@mail.gmail.com>

Heiko,

On Mon, May 23, 2016 at 7:58 AM, Heiko Stuebner <heiko at sntech.de> wrote:
> There are some more General Register Files used in devicetree files
> already, but as of now undocumented in the binding document, fix that.
>
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> ---
>  Documentation/devicetree/bindings/soc/rockchip/grf.txt | 4 ++++
>  1 file changed, 4 insertions(+)

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Mon May 23 13:53:20 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 23 May 2016 13:53:20 -0700
Subject: [PATCH v5 1/5] Documentation: mmc: add mmc-hs400-enhanced-strobe
In-Reply-To: <1463976812-29698-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <1463976812-29698-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAD=FV=XzP_r1BAz_EXieXSuVY3h5uSYkQhrEo+Ro9sX5aYrw4w@mail.gmail.com>

Shawn,

On Sun, May 22, 2016 at 9:13 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> mmc-hs400-enhanced-strobe is used to claim that the
> host can support hs400 mode with enhanced strobe
> introduced by emmc 5.1 spec.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> Acked-by: Rob Herring <robh at kernel.org>
> ---
>
> Changes in v5: None
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
>
>  Documentation/devicetree/bindings/mmc/mmc.txt | 1 +
>  1 file changed, 1 insertion(+)

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Mon May 23 13:53:32 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 23 May 2016 13:53:32 -0700
Subject: [PATCH v5 2/5] mmc: core: add mmc-hs400-enhanced-strobe support
In-Reply-To: <1463976823-29739-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <1463976823-29739-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAD=FV=Xoegu1cb6QtaDRPf9gz7BVKVw1sfzzKM7NDKpTXL0jvA@mail.gmail.com>

Shawn,

On Sun, May 22, 2016 at 9:13 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> This patch introduce mmc-hs400-enhanced-strobe for platforms
> which want to enable enhanced strobe function from DT if the
> mmc host controller claims to support enhanced strobe.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>
> ---
>
> Changes in v5:
> - avoid to call hs400_enhanced+_strobe in mmc_set_initial_state
>   if no setting MMC_CAP2_HS400_ES.
> - add Adrian's ack for patch[5/5]
>
> Changes in v4:
> - check avail_type with EXT_CSD_CARD_TYPE_HS400 instead of
>   card_type
> - check if host support 8-bit when selecting hs400es
> - some minor fix suggested by Douglas and add his review tag
>
> Changes in v3:
> - remove helper function and shorten cap2 to MMC_CAP2_HS400_ES
> - rename callback to hs400_enhanced_strobe and make it return void
> - add enhanced_strobe in mmc_ios and pass it to hs400_enhanced_strobe
> - disable host's enhanced strobe in mmc_set_initial_state
> - remove bus checking after switching hs400es
> - add new function for hs400es timing selection
> - fix wrong judgement of mmc_card_hs400es
>
> Changes in v2:
> - switch to HS400ES from Highspeed mode directly
>
>  drivers/mmc/core/host.c  | 2 ++
>  include/linux/mmc/host.h | 1 +
>  2 files changed, 3 insertions(+)

Reviewed-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Mon May 23 13:56:34 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 23 May 2016 13:56:34 -0700
Subject: [PATCH v5 4/5] mmc: debugfs: add HS400 enhanced strobe description
In-Reply-To: <1463976844-29821-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <1463976844-29821-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAD=FV=WFQ4aG-LhB=s6KhdoHtAjuQnaW6duyzh1LUKAHdDXvTA@mail.gmail.com>

Shawn,

On Sun, May 22, 2016 at 9:14 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> We introduce HS400 with enhanced strobe function, so we need
> to add it for debug show.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
>
> Changes in v5: None
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
>
>  drivers/mmc/core/debugfs.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 9382a57..51d7c38 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -148,7 +148,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>                 str = "mmc HS200";
>                 break;
>         case MMC_TIMING_MMC_HS400:
> -               str = "mmc HS400";
> +               mmc_card_hs400es(host->card) ?
> +                       (str = "mmc HS400 enhanced strobe") :
> +                       (str = "mmc HS400");

Not sure it's terribly important, but I've typically seen this as:

str = mmc_card_hs400es(host->card) ?
          "mmc HS400 enhanced strobe" : "mmc HS400";

AKA: don't repeat the "str ="

I doubt it really matters that much, though, so:

Reviewed-by: Douglas Anderson <dianders at chromium.org>
Tested-by: Douglas Anderson <dianders at chromium.org>


From dianders at chromium.org  Mon May 23 14:00:57 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 23 May 2016 14:00:57 -0700
Subject: [PATCH v5 5/5] mmc: sdhci-of-arasan: implement enhanced strobe
 callback
In-Reply-To: <1463976853-29862-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <1463976853-29862-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAD=FV=X5os7fsCrOh7pDLAt7CSyRw3Q76sFgh-NJhDni02sXdA@mail.gmail.com>

Shawn,

On Sun, May 22, 2016 at 9:14 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> Currently sdhci-arasan 5.1 can support enhanced strobe function,
> and we now limit it just for "arasan,sdhci-5.1". Add
> mmc-hs400-enhanced-strobe in DT to enable the function if we're
> sure our controller can support it.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> Acked-by: Adrian Hunter <adrian.hunter at intel.com>
> Reviewed-by: Doug Anderson <dianders at chromium.org>
> ---
>
> Changes in v5: None
> Changes in v4: None

Again, minor, but you did have changes...

> Changes in v3: None
> Changes in v2: None
>
>  drivers/mmc/host/sdhci-of-arasan.c | 20 ++++++++++++++++++++
>  1 file changed, 20 insertions(+)

I've tested this patch and it appears to work (not that I've hooked a
scope up, but since it's not doing tuning I think it would be pretty
obvious if it didn't work).

Tested-by: Douglas Anderson <dianders at chromium.org>


From robh at kernel.org  Mon May 23 14:38:34 2016
From: robh at kernel.org (Rob Herring)
Date: Mon, 23 May 2016 16:38:34 -0500
Subject: [PATCH 1/3] dt-bindings: add used but undocumented rockchip grf
 compatible values
In-Reply-To: <1464015539-19521-2-git-send-email-heiko@sntech.de>
References: <1464015539-19521-1-git-send-email-heiko@sntech.de>
 <1464015539-19521-2-git-send-email-heiko@sntech.de>
Message-ID: <20160523213834.GA12860@rob-hp-laptop>

On Mon, May 23, 2016 at 04:58:57PM +0200, Heiko Stuebner wrote:
> There are some more General Register Files used in devicetree files
> already, but as of now undocumented in the binding document, fix that.
> 
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> ---
>  Documentation/devicetree/bindings/soc/rockchip/grf.txt | 4 ++++
>  1 file changed, 4 insertions(+)

Acked-by: Rob Herring <robh at kernel.org>


From dianders at chromium.org  Mon May 23 17:39:32 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 23 May 2016 17:39:32 -0700
Subject: [PATCH v5 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <1463976835-29780-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <1463976835-29780-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <CAD=FV=WYB4Pg7HcXHVVN-rWAfrV8bGY+MhNFJ+DRJRbhcbXNpQ@mail.gmail.com>

Shawn,

On Sun, May 22, 2016 at 9:13 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
> Controllers use data strobe line to latch data from devices
> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
> introduces enhanced strobe mode for latching cmd response from
> emmc devices to host controllers. This new feature is optional,
> so it depends both on device's cap and host's cap to decide
> whether to use it or not.
>
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
>
> Changes in v5: None
> Changes in v4: None

Not terribly important, but things certainly did change in this patch
since previous versions.

> Changes in v3: None
> Changes in v2: None
>
>  drivers/mmc/core/bus.c   |  3 +-
>  drivers/mmc/core/core.c  |  9 ++++++
>  drivers/mmc/core/mmc.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
>  include/linux/mmc/card.h |  1 +
>  include/linux/mmc/host.h | 11 +++++++
>  include/linux/mmc/mmc.h  |  3 ++
>  6 files changed, 108 insertions(+), 3 deletions(-)

I don't see anything obviously bad about this patch, but I haven't
gone deep into all the details of mmc_select_hs400es(), so I'm not
sure I can really provide a full Reviewed tag.  At least I have tested
this, so:

Tested-by: Douglas Anderson <dianders at chromium.org>


From LinoSanfilippo at gmx.de  Mon May 23 18:09:49 2016
From: LinoSanfilippo at gmx.de (Lino Sanfilippo)
Date: Tue, 24 May 2016 03:09:49 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160522223659.GB5086@electric-eye.fr.zoreil.com>
References: <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com> <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com> <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm> <5740E82F.8040903@gmx.de>
 <20160522091742.GA8681@debian-dorm> <57419853.9050701@gmx.de>
 <20160522223659.GB5086@electric-eye.fr.zoreil.com>
Message-ID: <5743A9DD.8010202@gmx.de>

On 23.05.2016 00:36, Francois Romieu wrote:
> Lino Sanfilippo <LinoSanfilippo at gmx.de> :
> [...]
>> --- a/drivers/net/ethernet/arc/emac_main.c
>> +++ b/drivers/net/ethernet/arc/emac_main.c
>> @@ -159,12 +159,22 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>>  		unsigned int *txbd_dirty = &priv->txbd_dirty;
>>  		struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
>>  		struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
>> -		struct sk_buff *skb = tx_buff->skb;
>>  		unsigned int info = le32_to_cpu(txbd->info);
>> +		struct sk_buff *skb;
>>  
> 
> Insert a smp_rmb() here to close one window for an outdated txbd_dirty value
> (the "arc_emac_tx_clean wrote txbd_curr and issued smp_wmb" one).
> 
> Actually, insert smp_rmb() at the start of arc_emac_tx_clean() as it
> does not need to be performed withing the loop and would penalize it.

I agree, we should place the barrier before the loop. I also think it is indeed more
appropriate to use the SMP versions for both barriers.

> 
> Given the implicit smp barriers in the non-driver code, I consider
> "arc_emac_tx_clean on one CPU does not read latest txbd_dirty value written
> by previous arc_emac_tx_clean on different CPU" as utter onanism but
> issueing smp_rmb() at the start of arc_emac_tx_clean() nails it as well.
> 
>> -		if ((info & FOR_EMAC) || !txbd->data || !skb)
>> +		if (*txbd_dirty == priv->txbd_curr)
>>  			break;
> 
> Ok, it's just the "while (priv->txbd_dirty != priv->txbd_curr) {" loop
> in disguise.

I cant deny that :)

> 
>>  
>> +		/* Make sure curr pointer is consistent with info */
>> +		rmb();
>> +
>> +		info = le32_to_cpu(txbd->info);
>> +
>> +		if (info & FOR_EMAC)
>> +			break;
> 
> With proper ordering + barrier in arc_emac_tx() you can relax it to smp_rmb().

Ok.

>> +
>> +		skb = tx_buff->skb;
>> +
>>  		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
>>  			stats->tx_errors++;
>>  			stats->tx_dropped++;
>> @@ -195,8 +205,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>>  		*txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;
>>  	}
>>  
>> -	/* Ensure that txbd_dirty is visible to tx() before checking
>> -	 * for queue stopped.
>> +	/* Ensure that txbd_dirty is visible to tx() and we see the most recent
>> +	 * value for txbd_curr.
>>  	 */
>>  	smp_mb();
>>  
>> @@ -680,35 +690,29 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
>>  	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
>>  
>>  	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
>> -
>> -	/* Make sure pointer to data buffer is set */
>> -	wmb();
>> +	priv->tx_buff[*txbd_curr].skb = skb;
>>  
>>  	skb_tx_timestamp(skb);
>>  
>>  	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
> 
> No.
> 
> You need dma_wmb() after skb_tx_timestamp() to commit skb_tx_timestamp() [*]
> and data = cpu_to_le32(addr).

I dont agree here. A dma_wmb would have an effect to "data" and "info", yes, but it 
would have absolutely no effect to skb_tx_timestamp(), since there is no dma access
involved here. In fact skb_tx_timestamp() could probably be even reordered to appear
 after the dma_wmb.
Anyway, there is the wmb() directly after the assignment to "info". _This_ barrier
 should ensure that skb_tx_timestamp() (along with a flush of data and info to DMA)
is executed before "txbd_curr" is advanced.
This means that the corresponding skb cant be freed prematurely by tx_clean().

 
> 
> [*] I doubt anyone want a dma_sync_single_...() here.
> 
>>  
>> -	/* Make sure info word is set */
>> +	/* 1. Make sure that with respect to tx_clean everything is set up
>> +	 * properly before we advance txbd_curr.
>> +	 * 2. Make sure writes to DMA descriptors are completed before we inform
>> +	 * the hardware.
>> +	 */
>>  	wmb();
> 
> Yes, either wmb() or smp_wmb() + dma_wmb().
> 

I really prefer one generic barrier over combos of 2 or more special barriers.

>>  
>> -	priv->tx_buff[*txbd_curr].skb = skb;
>> -
>>  	/* Increment index to point to the next BD */
>>  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
>>  
>> -	/* Ensure that tx_clean() sees the new txbd_curr before
>> -	 * checking the queue status. This prevents an unneeded wake
>> -	 * of the queue in tx_clean().
>> +	/* Ensure we see the most recent value of txbd_dirty and tx_clean() sees
>> +	 * the updated value of txbd_curr.
>>  	 */
>>  	smp_mb();
> 
> Nit: s/the most/a/
> 
> "a" as in "arc_emac_tx_clean() _is_ racing with arc_emac_tx"
> 
>>  
>> -	if (!arc_emac_tx_avail(priv)) {
>> +	if (!arc_emac_tx_avail(priv))
>>  		netif_stop_queue(ndev);
>> -		/* Refresh tx_dirty */
>> -		smp_mb();
>> -		if (arc_emac_tx_avail(priv))
>> -			netif_start_queue(ndev);
>> -	}
> 
> No.
> 
> I may sound like an old record but the revalidation part must be kept.
> 
> txbd_dirty may change in the arc_emac_tx_avail.. netif_stop_queue window
> (the race requires a different CPU as arc_emac_tx() runs in locally
> disabled BH context).
> 

Ok, I can see the race now. So yes, this should be kept.

I will prepare a patch with the discussed changes tomorrow.

Regards,
Lino





From LinoSanfilippo at gmx.de  Mon May 23 18:14:47 2016
From: LinoSanfilippo at gmx.de (Lino Sanfilippo)
Date: Tue, 24 May 2016 03:14:47 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160523113609.GA21019@debian-dorm>
References: <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com> <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com> <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm> <5740E82F.8040903@gmx.de>
 <20160522091742.GA8681@debian-dorm> <57419853.9050701@gmx.de>
 <20160523113609.GA21019@debian-dorm>
Message-ID: <5743AB07.5020206@gmx.de>

On 23.05.2016 13:36, Shuyu Wei wrote:
> On Sun, May 22, 2016 at 01:30:27PM +0200, Lino Sanfilippo wrote:
>> 

> 
> Hi Lino, 
> This patch worked after a whole night of stress testing.
> 

Thats great! I will nevertheless make the changes discussed with Francois and hopefully we have a final
solution, soon.

Regards,
Lino




From shawn.lin at rock-chips.com  Mon May 23 18:28:55 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 24 May 2016 09:28:55 +0800
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <8520D5D51A55D047800579B094147198258ACE47@XAP-PVEXMBX01.xlnx.xilinx.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
 <8520D5D51A55D047800579B094147198258ACE47@XAP-PVEXMBX01.xlnx.xilinx.com>
Message-ID: <0f470ba9-78ac-4822-2cd0-6f028123271d@rock-chips.com>

Hi Bharat,

On 2016/5/23 23:15, Bharat Kumar Gogada wrote:
>> +
>> +	irq = platform_get_irq_byname(pdev, "pcie-sys");
>> +	if (irq < 0) {
>> +		dev_err(dev, "missing pcie_sys IRQ resource\n");
>> +		return -EINVAL;
>> +	}
>> +	err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler,
>> +			       IRQF_SHARED, "pcie-sys", port);
>> +	if (err) {
>> +		dev_err(dev, "failed to request pcie subsystem irq\n");
>> +		return err;
>> +	}
>> +
>> +	port->irq = platform_get_irq_byname(pdev, "pcie-legacy");
>> +	if (port->irq < 0) {
>> +		dev_err(dev, "missing pcie_legacy IRQ resource\n");
>> +		return -EINVAL;
>> +	}
>> +	err = devm_request_irq(dev, port->irq,
>> +			       rockchip_pcie_legacy_int_handler,
>> +			       IRQF_SHARED,
>> +			       "pcie-legacy",
>> +			       port);
>> +	if (err) {
>> +		dev_err(&pdev->dev, "failed to request pcie-legacy irq\n");
>> +		return err;
>> +	}
>> +
>> +	irq = platform_get_irq_byname(pdev, "pcie-client");
>> +	if (irq < 0) {
>> +		dev_err(dev, "missing pcie-client IRQ resource\n");
>> +		return -EINVAL;
>> +	}
>> +	err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler,
>> +			       IRQF_SHARED, "pcie-client", port);
>> +	if (err) {
>> +		dev_err(dev, "failed to request pcie client irq\n");
>> +		return err;
>> +	}
>> +
>
> All of the above interrupt number details are being obtained from device tree, why not move above API's to rockchip_pcie_parse_dt.

Ok, I will move these above into parse_dt function.

>
>> +	port->dev = dev;
>> +	err = rockchip_pcie_parse_dt(port);
>> +	if (err) {
>> +		dev_err(dev, "Parsing DT failed\n");
>> +		return err;
>> +	}
>> +
>> +	pcie_write(port, 0x6040000, PCIE_RC_CONFIG_BASE + 0x8);
>> +	pcie_write(port, 0x0, PCIE_CORE_CTRL_MGMT_BASE + 0x300);
>> +
>> +	pcie_write(port, (RC_REGION_0_ADDR_TRANS_L +
>> RC_REGION_0_PASS_BITS),
>> +		   PCIE_CORE_AXI_CONF_BASE);
>> +	pcie_write(port, RC_REGION_0_ADDR_TRANS_H,
>> +		   PCIE_CORE_AXI_CONF_BASE + 0x4);
>> +	pcie_write(port, 0x0080000a, PCIE_CORE_AXI_CONF_BASE + 0x8);
>> +	pcie_write(port, 0x00000000, PCIE_CORE_AXI_CONF_BASE + 0xc);
>
> Why not move the above steps to rockchip_pcie_init_port function ?
> Please use macros instead of using values.

okay, will improve them.

Thanks for comment.

>
>
>


-- 
Best Regards
Shawn Lin



From zhengxing at rock-chips.com  Mon May 23 18:36:14 2016
From: zhengxing at rock-chips.com (Xing Zheng)
Date: Tue, 24 May 2016 09:36:14 +0800
Subject: [RESEND PATCH v2] ASoC: rockchip: Add machine driver for
 MAX98357A/RT5514/DA7219
Message-ID: <1464053774-15914-1-git-send-email-zhengxing@rock-chips.com>

There are multi codec devices on the RK3399 platform, we can use
this patch support and control these codecs.

Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
---

Changes in v2:
- use the FS 256 to set mclks of the max98357a and rt5514 danamically
- add more sample rate for da7219

 .../sound/rockchip-max98357a-rt5514-da7219.txt     |   15 +
 sound/soc/rockchip/Kconfig                         |   11 +
 sound/soc/rockchip/Makefile                        |    2 +
 .../rockchip/rockchip_max98357a_rt5514_da7219.c    |  333 ++++++++++++++++++++
 4 files changed, 361 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
 create mode 100644 sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c

diff --git a/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
new file mode 100644
index 0000000..5928384
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
@@ -0,0 +1,15 @@
+ROCKCHIP with MAX98357A/RT5514/DA7219 codecs
+
+Required properties:
+- compatible: "rockchip,rockchip-sound"
+- rockchip,cpu: The phandle of the Rockchip I2S controller that's
+  connected to the codecs
+- rockchip,codec: The phandle of the MAX98357A/RT5514/DA7219 codecs
+
+Example:
+
+sound {
+	compatible = "rockchip,rockchip-sound";
+	rockchip,cpu = <&i2s0 &i2s0 &i2s1>;
+	rockchip,codec = <&max98357a &headsetcodec &codec>;
+};
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index f1e0c70..d02aa94 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -41,3 +41,14 @@ config SND_SOC_ROCKCHIP_RT5645
 	help
 	  Say Y or M here if you want to add support for SoC audio on Rockchip
 	  boards using the RT5645/RT5650 codec, such as Veyron.
+
+config SND_SOC_ROCKCHIP_MAX98357A_RT5514_DA7219
+	tristate "ASoC support for Rockchip boards using the MAX98357A/RT5514/DA7219"
+	depends on SND_SOC_ROCKCHIP && GPIOLIB
+	select SND_SOC_ROCKCHIP_I2S
+	select SND_SOC_MAX98357A
+	select SND_SOC_RT5514
+	select SND_SOC_DA7219
+	help
+	  Say Y or M here if you want to add support for SoC audio on Rockchip
+	  boards using the MAX98357A/RT5514/DA7219.
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index c0bf560..ca97489 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
 
 snd-soc-rockchip-max98090-objs := rockchip_max98090.o
 snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
+snd-soc-rockchip-max98357a-rt5514-da7219-objs := rockchip_max98357a_rt5514_da7219.o
 
 obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
+obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98357A_RT5514_DA7219) += snd-soc-rockchip-max98357a-rt5514-da7219.o
diff --git a/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c b/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c
new file mode 100644
index 0000000..818c47e
--- /dev/null
+++ b/sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c
@@ -0,0 +1,333 @@
+/*
+ * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
+ *
+ * Copyright (c) 2016, ROCKCHIP CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "rockchip_i2s.h"
+#include "../codecs/da7219.h"
+#include "../codecs/da7219-aad.h"
+#include "../codecs/rt5514.h"
+
+#define DRV_NAME "rockchip-sound"
+
+#define SOUND_FS	256
+
+static struct snd_soc_jack rockchip_sound_jack;
+
+static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphones", NULL),
+	SND_SOC_DAPM_SPK("Speakers", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route rockchip_dapm_routes[] = {
+	/* Input Lines */
+	{"MIC", NULL, "Headset Mic"},
+	{"DMIC1L", NULL, "Int Mic"},
+	{"DMIC1R", NULL, "Int Mic"},
+
+	/* Output Lines */
+	{"Headphones", NULL, "HPL"},
+	{"Headphones", NULL, "HPR"},
+	{"Speakers", NULL, "Speakers"},
+};
+
+static const struct snd_kcontrol_new rockchip_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphones"),
+	SOC_DAPM_PIN_SWITCH("Speakers"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Int Mic"),
+};
+
+static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+	unsigned int mclk;
+	int ret;
+
+	/* max98357a supports these sample rates */
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		mclk = params_rate(params) * SOUND_FS;
+		break;
+	default:
+		dev_err(rtd->card->dev, "%s() doesn't support this sample rate: %d\n",
+				__func__, params_rate(params));
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
+	if (ret) {
+		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
+				__func__, mclk, ret);
+		return ret;
+	}
+
+	snd_soc_dapm_disable_pin(dapm, "Headphones");
+	snd_soc_dapm_enable_pin(dapm, "Speakers");
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	unsigned int mclk;
+	int ret;
+
+	mclk = params_rate(params) * SOUND_FS;
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+				     SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,
+				     mclk, SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
+				__func__, params_rate(params) * 512, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+	int mclk, ret;
+
+	/* in bypass mode, the mclk has to be one of the frequencies below */
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 24000:
+	case 32000:
+	case 48000:
+	case 64000:
+	case 96000:
+		mclk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+	case 88200:
+		mclk = 11289600;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+				     SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);
+		return ret;
+	}
+
+	snd_soc_dapm_disable_pin(dapm, "Speakers");
+	snd_soc_dapm_enable_pin(dapm, "Headphones");
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec_dais[0]->codec;
+	int ret;
+
+	/* Enable Headset and 4 Buttons Jack detection */
+	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+				    SND_JACK_HEADSET |
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
+				    &rockchip_sound_jack, NULL, 0);
+
+	if (ret) {
+		dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);
+		return ret;
+	}
+
+	da7219_aad_jack_det(codec, &rockchip_sound_jack);
+
+	return 0;
+}
+
+static struct snd_soc_ops rockchip_sound_max98357a_ops = {
+	.hw_params = rockchip_sound_max98357a_hw_params,
+};
+
+static struct snd_soc_ops rockchip_sound_rt5514_ops = {
+	.hw_params = rockchip_sound_rt5514_hw_params,
+};
+
+static struct snd_soc_ops rockchip_sound_da7219_ops = {
+	.hw_params = rockchip_sound_da7219_hw_params,
+};
+
+enum {
+	DAILINK_MAX98357A,
+	DAILINK_RT5514,
+	DAILINK_DA7219,
+};
+
+static struct snd_soc_dai_link rockchip_dailinks[] = {
+	[DAILINK_MAX98357A] = {
+		.name = "MAX98357A",
+		.stream_name = "MAX98357A PCM",
+		.codec_dai_name = "HiFi",
+		.ops = &rockchip_sound_max98357a_ops,
+		/* set max98357a as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+	[DAILINK_RT5514] = {
+		.name = "RT5514",
+		.stream_name = "RT5514 PCM",
+		.codec_dai_name = "rt5514-aif1",
+		.ops = &rockchip_sound_rt5514_ops,
+		/* set rt5514 as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+	[DAILINK_DA7219] = {
+		.name = "DA7219",
+		.stream_name = "DA7219 PCM",
+		.codec_dai_name = "da7219-hifi",
+		.init = rockchip_sound_da7219_init,
+		.ops = &rockchip_sound_da7219_ops,
+		/* set da7219 as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+};
+
+static struct snd_soc_card rockchip_sound_card = {
+	.name = "rockchip-sound",
+	.owner = THIS_MODULE,
+	.dai_link = rockchip_dailinks,
+	.num_links =  ARRAY_SIZE(rockchip_dailinks),
+	.dapm_widgets = rockchip_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
+	.dapm_routes = rockchip_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
+	.controls = rockchip_controls,
+	.num_controls = ARRAY_SIZE(rockchip_controls),
+};
+
+static int rockchip_sound_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &rockchip_sound_card;
+	struct device_node *cpu_node;
+	int i, ret;
+
+	for (i = 0; i < card->num_links; i++) {
+		cpu_node = of_parse_phandle(pdev->dev.of_node,
+					 "rockchip,cpu", i);
+		if (!cpu_node) {
+			dev_err(&pdev->dev, "Property[%d] 'rockchip,cpu' missing or invalid\n", i);
+			return -EINVAL;
+		}
+
+		rockchip_dailinks[i].platform_of_node = cpu_node;
+		rockchip_dailinks[i].cpu_of_node = cpu_node;
+
+		rockchip_dailinks[i].codec_of_node =
+			of_parse_phandle(pdev->dev.of_node, "rockchip,codec", i);
+		if (!rockchip_dailinks[i].codec_of_node) {
+			dev_err(&pdev->dev,
+				"Property[%d] 'rockchip,codec' missing or invalid\n", i);
+			return -EINVAL;
+		}
+	}
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static const struct of_device_id rockchip_sound_of_match[] = {
+	{ .compatible = "rockchip,rockchip-sound", },
+	{},
+};
+
+static struct platform_driver rockchip_sound_driver = {
+	.probe = rockchip_sound_probe,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = rockchip_sound_of_match,
+#ifdef CONFIG_PM
+		.pm = &snd_soc_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(rockchip_sound_driver);
+
+MODULE_AUTHOR("Xing Zheng <zhengxing at rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);
-- 
1.7.9.5




From zhengxing at rock-chips.com  Mon May 23 18:38:24 2016
From: zhengxing at rock-chips.com (Xing Zheng)
Date: Tue, 24 May 2016 09:38:24 +0800
Subject: [PATCH v2] ASoC: rockchip: Add machine driver for
 MAX98357A/RT5514/DA7219
In-Reply-To: <6209835.s95gRr0Nsp@phil>
References: <1464014612-14396-1-git-send-email-zhengxing@rock-chips.com>
 <6209835.s95gRr0Nsp@phil>
Message-ID: <5743B090.50401@rock-chips.com>

Hi Heiko,

On 2016?05?23? 22:51, Heiko Stuebner wrote:
> Hi Xing,
>
> Am Montag, 23. Mai 2016, 22:43:32 schrieb Xing Zheng:
>> There are multi codec devices on the RK3399 platform, we can use
>> this patch support and control these codecs.
>>
>> ---
>>
>> Changes in v2:
>> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
> something seems to have gone wrong here.
>
> The Signed-off needs to be above the "---" and the changelog itself seems
> empty while at least the number of lines in your
> rockchip_max98357a_rt5514_da7219.c seems to have changed.
>
Sorry to forgot to add the changelog. I resent this patch_v2.

Thank you for your reminding.

-- 
- Xing Zheng




From shawn.lin at rock-chips.com  Mon May 23 18:42:09 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 24 May 2016 09:42:09 +0800
Subject: [PATCH 1/2] Documentation: add binding description of Rockchip
 PCIe controller
In-Reply-To: <35714508.Tep5CcJBvk@phil>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <3930626.4a3xBnzHhK@phil>
 <766c3fc9-7e92-6235-76d5-803cc116845a@rock-chips.com>
 <35714508.Tep5CcJBvk@phil>
Message-ID: <78de1cf5-e23d-d217-2d68-bdd8c6e4b477@rock-chips.com>

On 2016/5/24 3:53, Heiko Stuebner wrote:
> Am Samstag, 21. Mai 2016, 11:55:35 schrieb Shawn Lin:
>> On 2016/5/20 19:20, Heiko Stuebner wrote:
>>> Hi Shawn,
>>>
>>> Am Freitag, 20. Mai 2016, 18:29:06 schrieb Shawn Lin:
>>>> This patch add some required and optional properties for Rockchip
>>>> PCIe controller. Also we add a example for how to use it.
>>>>
>>>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>>>
>>>> ---
>
> [...]
>
>>>> +- msi-parent: Link to the hardware entity that serves as the Message
>>>> +- pinctrl-names : The pin control state names
>>>> +- pinctrl-0: The "default" pinctrl state
>>>
>>> I'm not sure if pinctrl-properties need to be described when you don't
>>> need special handling in the form of additional pin states. The pcie
>>> part does not do any pin-handling of its own.
>>
>> We need it in prevention of any firmwares change the default state
>> of #CLKREQ which is useful for ASPM. Also we have a backup pin for
>> clkreqn called clkreqnb, which should be taken more consideration since
>> when refering to any one of these two, pinctrl should configure the
>> bit[14] of GRF_SOC_CON7 automatically. But it is unfortunately beyound
>> the implementation of pinctrl-rk3399.
>>
>> BTW, I don't know if we wanna support this action inside the pinctrl
>> code?
>
> The TRM says for me for that bit only "pcie_clkreq_sel port control" and
> that naming really suggests that it is a property of the pcie controller,
> not the generic pinctrl. So if this needs to be touched the pcie controller
> needs to do it.

I don't agree that pcie controller should do it. As a common driver, it
should not care two much setting related to io selection which is very
likely to be changed in the future Socs. Shuld it always keep a
reference to bit[ABC] of GRF_SOC_CONXYZ, and should it adds some code
to see which IO is selected for #CLKREQ?

Currently I do it in firmware, but it's worth to make some discussion
as there are also some IO backup slelections the GRF of RK3399. Anyway,
let's skip this topic from the $SUBJECT patch.

>
>
>>>> +- interrupt-map-mask and interrupt-map: standard PCI properties
>>>> +- interrupt-controller: identifies the node as an interrupt controller
>>>> +
>>>> +Optional Property:
>>>> +- ep-gpios: contain the entry for pre-reset gpio
>>>> +- num-lanes: number of lanes to use
>>>> +- assigned-clocks, assigned-clock-parents and assigned-clock-rates:
>>>> standard +		   clock bindings. See ../clock/clock-bindings.txt
>>>
>>> Again that (assigned-clocks handling) is not actual part of the pci-
>>> controllers actions, but other parts and also described already
>>> elsewhere.
>> Basically it does. But this is an alternative choice for pcie-phy to
>> generate the ref_clk. When we want 100MHz src clk for PLL inside the
>> pcie-phy?we should add them, otherwise it's taken from xin 24MHz.
>>
>> This is useful for SI testing or some others special cases. So should we
>> add it as an option and leave a sample here?
>
> What I meant was that while clock handling is important when looking at the
> whole system, the pcie controller itself does only care that it gets a
> clock, but not that much where you get it from.
>
> So while assigned-clocks has its place in the real devicetree, I don't think
> it is an element of the actual pcie-controller binding.

Oh, I see.. So it seems good to keep all the assigned-clocks in on
place. I will remove it from this patch.

>
>
> Heiko
>
>
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Mon May 23 18:52:32 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 24 May 2016 09:52:32 +0800
Subject: [PATCH v5 4/5] mmc: debugfs: add HS400 enhanced strobe description
In-Reply-To: <CAD=FV=WFQ4aG-LhB=s6KhdoHtAjuQnaW6duyzh1LUKAHdDXvTA@mail.gmail.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <1463976844-29821-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=WFQ4aG-LhB=s6KhdoHtAjuQnaW6duyzh1LUKAHdDXvTA@mail.gmail.com>
Message-ID: <c6137b5e-c77e-bb54-cf0a-c23e7714dfb1@rock-chips.com>

? 2016/5/24 4:56, Doug Anderson ??:
> Shawn,
>
> On Sun, May 22, 2016 at 9:14 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> We introduce HS400 with enhanced strobe function, so we need
>> to add it for debug show.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> ---
>>
>> Changes in v5: None
>> Changes in v4: None
>> Changes in v3: None
>> Changes in v2: None
>>
>>  drivers/mmc/core/debugfs.c | 4 +++-
>>  1 file changed, 3 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
>> index 9382a57..51d7c38 100644
>> --- a/drivers/mmc/core/debugfs.c
>> +++ b/drivers/mmc/core/debugfs.c
>> @@ -148,7 +148,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>>                 str = "mmc HS200";
>>                 break;
>>         case MMC_TIMING_MMC_HS400:
>> -               str = "mmc HS400";
>> +               mmc_card_hs400es(host->card) ?
>> +                       (str = "mmc HS400 enhanced strobe") :
>> +                       (str = "mmc HS400");
>
> Not sure it's terribly important, but I've typically seen this as:
>
> str = mmc_card_hs400es(host->card) ?
>           "mmc HS400 enhanced strobe" : "mmc HS400";
>
> AKA: don't repeat the "str ="
>

Thanks for your review and test. I wanna wait for some more days
to see if there are any other comments for this patchset.


> I doubt it really matters that much, though, so:
>
> Reviewed-by: Douglas Anderson <dianders at chromium.org>
> Tested-by: Douglas Anderson <dianders at chromium.org>
>
>
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Mon May 23 18:55:05 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 24 May 2016 09:55:05 +0800
Subject: [PATCH v5 5/5] mmc: sdhci-of-arasan: implement enhanced strobe
 callback
In-Reply-To: <CAD=FV=X5os7fsCrOh7pDLAt7CSyRw3Q76sFgh-NJhDni02sXdA@mail.gmail.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <1463976853-29862-1-git-send-email-shawn.lin@rock-chips.com>
 <CAD=FV=X5os7fsCrOh7pDLAt7CSyRw3Q76sFgh-NJhDni02sXdA@mail.gmail.com>
Message-ID: <e22866dd-c2d2-e210-e240-9f649cda3e3f@rock-chips.com>

? 2016/5/24 5:00, Doug Anderson ??:
> Shawn,
>
> On Sun, May 22, 2016 at 9:14 PM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>> Currently sdhci-arasan 5.1 can support enhanced strobe function,
>> and we now limit it just for "arasan,sdhci-5.1". Add
>> mmc-hs400-enhanced-strobe in DT to enable the function if we're
>> sure our controller can support it.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> Acked-by: Adrian Hunter <adrian.hunter at intel.com>
>> Reviewed-by: Doug Anderson <dianders at chromium.org>
>> ---
>>
>> Changes in v5: None
>> Changes in v4: None
>
> Again, minor, but you did have changes...

yes, it did. I moved all the change-log into the
cover-letter but it seems better to keep them seperately
for each patch. I will do it for the next version if
needed. Thanks.

>
>> Changes in v3: None
>> Changes in v2: None
>>
>>  drivers/mmc/host/sdhci-of-arasan.c | 20 ++++++++++++++++++++
>>  1 file changed, 20 insertions(+)
>
> I've tested this patch and it appears to work (not that I've hooked a
> scope up, but since it's not doing tuning I think it would be pretty
> obvious if it didn't work).
>
> Tested-by: Douglas Anderson <dianders at chromium.org>
>
>
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Mon May 23 19:05:58 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 24 May 2016 10:05:58 +0800
Subject: [PATCH 1/3] dt-bindings: add used but undocumented rockchip grf
 compatible values
In-Reply-To: <1464015539-19521-2-git-send-email-heiko@sntech.de>
References: <1464015539-19521-1-git-send-email-heiko@sntech.de>
 <1464015539-19521-2-git-send-email-heiko@sntech.de>
Message-ID: <a31feead-5bc1-a77d-d4c5-111b7ba82b9d@rock-chips.com>

? 2016/5/23 22:58, Heiko Stuebner ??:
> There are some more General Register Files used in devicetree files
> already, but as of now undocumented in the binding document, fix that.
>
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> ---

Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>

>  Documentation/devicetree/bindings/soc/rockchip/grf.txt | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/Documentation/devicetree/bindings/soc/rockchip/grf.txt b/Documentation/devicetree/bindings/soc/rockchip/grf.txt
> index 013e71a..c6e62cb 100644
> --- a/Documentation/devicetree/bindings/soc/rockchip/grf.txt
> +++ b/Documentation/devicetree/bindings/soc/rockchip/grf.txt
> @@ -5,11 +5,13 @@ is composed of many registers for system control.
>
>  From RK3368 SoCs, the GRF is divided into two sections,
>  - GRF, used for general non-secure system,
> +- SGRF, used for general secure system,
>  - PMUGRF, used for always on system
>
>  Required Properties:
>
>  - compatible: GRF should be one of the followings
> +   - "rockchip,rk3036-grf", "syscon": for rk3036
>     - "rockchip,rk3066-grf", "syscon": for rk3066
>     - "rockchip,rk3188-grf", "syscon": for rk3188
>     - "rockchip,rk3228-grf", "syscon": for rk3228
> @@ -19,6 +21,8 @@ Required Properties:
>  - compatible: PMUGRF should be one of the followings
>     - "rockchip,rk3368-pmugrf", "syscon": for rk3368
>     - "rockchip,rk3399-pmugrf", "syscon": for rk3399
> +- compatible: SGRF should be one of the following
> +   - "rockchip,rk3288-sgrf", "syscon": for rk3288
>  - reg: physical base address of the controller and length of memory mapped
>    region.
>
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Mon May 23 19:09:41 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 24 May 2016 10:09:41 +0800
Subject: [PATCH 3/3] ARM: rockchip: drop rk3288 jtag/mmc switch handling
In-Reply-To: <1464015539-19521-4-git-send-email-heiko@sntech.de>
References: <1464015539-19521-1-git-send-email-heiko@sntech.de>
 <1464015539-19521-4-git-send-email-heiko@sntech.de>
Message-ID: <feee590b-e9a9-7c36-cf99-9dd1cb229eb7@rock-chips.com>

? 2016/5/23 22:58, Heiko Stuebner ??:
> We moved that functionality to a more generic place where it can also
> be used for other socs, so drop it from architecture code.
>
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>

It looks good to drop this Soc related setting from
architecture code.

Reviewed-by: Shawn Lin <shawn.lin at rock-chips.com>

> ---
>  arch/arm/mach-rockchip/rockchip.c | 12 ------------
>  1 file changed, 12 deletions(-)
>
> diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
> index beb71da..e7b2aa7 100644
> --- a/arch/arm/mach-rockchip/rockchip.c
> +++ b/arch/arm/mach-rockchip/rockchip.c
> @@ -29,13 +29,11 @@
>  #include "core.h"
>  #include "pm.h"
>
> -#define RK3288_GRF_SOC_CON0 0x244
>  #define RK3288_TIMER6_7_PHYS 0xff810000
>
>  static void __init rockchip_timer_init(void)
>  {
>  	if (of_machine_is_compatible("rockchip,rk3288")) {
> -		struct regmap *grf;
>  		void __iomem *reg_base;
>
>  		/*
> @@ -54,16 +52,6 @@ static void __init rockchip_timer_init(void)
>  		} else {
>  			pr_err("rockchip: could not map timer7 registers\n");
>  		}
> -
> -		/*
> -		 * Disable auto jtag/sdmmc switching that causes issues
> -		 * with the mmc controllers making them unreliable
> -		 */
> -		grf = syscon_regmap_lookup_by_compatible("rockchip,rk3288-grf");
> -		if (!IS_ERR(grf))
> -			regmap_write(grf, RK3288_GRF_SOC_CON0, 0x10000000);
> -		else
> -			pr_err("rockchip: could not get grf syscon\n");
>  	}
>
>  	of_clk_init(NULL);
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Mon May 23 19:22:09 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 24 May 2016 10:22:09 +0800
Subject: [PATCH 2/3] soc: rockchip: add driver handling grf setup
In-Reply-To: <1464015539-19521-3-git-send-email-heiko@sntech.de>
References: <1464015539-19521-1-git-send-email-heiko@sntech.de>
 <1464015539-19521-3-git-send-email-heiko@sntech.de>
Message-ID: <6a6e87ee-688d-90a3-2407-22847bd80971@rock-chips.com>

Hi Heiko,

On 2016/5/23 22:58, Heiko Stuebner wrote:
> The General Register Files are an area of registers containing a lot
> of single-bit settings for numerous components as well full components
> like usbphy control. Therefore all used components are accessed
> via the syscon provided by the grf nodes or from the sub-devices
> created through the simple-mfd created from the grf node.
>
> Some settings are not used by anything but will need to be set up
> according to expectations on the kernel side.
>
> Best example is the force_jtag setting, which defaults to on and
> results in the soc switching the pin-outputs between jtag and sdmmc
> automatically depending on the card-detect status. This conflicts
> heavily with how the dw_mmc driver expects to do its work and also
> with the clock-controller, which has most likely deactivated the
> jtag clock due to it being unused.

I agree we should disable force_jtag for real product. But on my local
branch we add a callback to parse a tag from cmdline. Sometime it's
useful for debugging in case of we need to setup JTAG for reproducing
and comfirming serious issue in which state the CPU cannot reponse to
any console input or FIQ-debug triggering.

Should we need it for upstream as you move all related code in this
new driver?  I'm not sure.

>
> So far the handling of this setting was living in the mach-rockchip
> code for the arm32-based rk3288 but that of course doesn't work
> for arm64 socs and would also look ugly for further arm32 socs.
>
> So introduce a top-level driver for the grf that handles these
> settings that need to be a certain way but nobody cares about.
>
> Signed-off-by: Heiko Stuebner <heiko at sntech.de>
> ---
>  drivers/soc/rockchip/Kconfig  |  10 +++
>  drivers/soc/rockchip/Makefile |   1 +
>  drivers/soc/rockchip/grf.c    | 138 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 149 insertions(+)
>  create mode 100644 drivers/soc/rockchip/grf.c
>
> diff --git a/drivers/soc/rockchip/Kconfig b/drivers/soc/rockchip/Kconfig
> index 7140ff8..20da55d 100644
> --- a/drivers/soc/rockchip/Kconfig
> +++ b/drivers/soc/rockchip/Kconfig
> @@ -3,6 +3,16 @@ if ARCH_ROCKCHIP || COMPILE_TEST
>  #
>  # Rockchip Soc drivers
>  #
> +
> +config ROCKCHIP_GRF
> +	bool
> +	default y
> +	help
> +	  The General Register Files are a central component providing
> +	  special additional settings registers for a lot of soc-components.
> +	  In a lot of cases there also need to be default settings initialized
> +	  to make some of them conform to expectations of the kernel.
> +
>  config ROCKCHIP_PM_DOMAINS
>          bool "Rockchip generic power domain"
>          depends on PM
> diff --git a/drivers/soc/rockchip/Makefile b/drivers/soc/rockchip/Makefile
> index 3d73d06..c851fa0 100644
> --- a/drivers/soc/rockchip/Makefile
> +++ b/drivers/soc/rockchip/Makefile
> @@ -1,4 +1,5 @@
>  #
>  # Rockchip Soc drivers
>  #
> +obj-$(CONFIG_ROCKCHIP_GRF) += grf.o
>  obj-$(CONFIG_ROCKCHIP_PM_DOMAINS) += pm_domains.o
> diff --git a/drivers/soc/rockchip/grf.c b/drivers/soc/rockchip/grf.c
> new file mode 100644
> index 0000000..25a1fd3
> --- /dev/null
> +++ b/drivers/soc/rockchip/grf.c
> @@ -0,0 +1,138 @@
> +/*
> + * Rockchip Generic Register Files setup
> + *
> + * Copyright (c) 2016 Heiko Stuebner <heiko at sntech.de>
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#include <linux/err.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +#define HIWORD_UPDATE(val, mask, shift) \
> +		((val) << (shift) | (mask) << ((shift) + 16))
> +
> +struct rockchip_grf_value {
> +	const char *desc;
> +	u32 reg;
> +	u32 val;
> +};
> +
> +struct rockchip_grf_info {
> +	const struct rockchip_grf_value *values;
> +	int num_values;
> +};
> +
> +#define RK3036_GRF_SOC_CON0		0x140
> +
> +static const struct rockchip_grf_value rk3036_defaults[] = {
> +	/*
> +	 * Disable auto jtag/sdmmc switching that causes issues with the
> +	 * clock-framework and the mmc controllers making them unreliable.
> +	 */
> +	{ "jtag switching", RK3036_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 11) },
> +};
> +
> +static const struct rockchip_grf_info rk3036_grf = {
> +	.values = rk3036_defaults,
> +	.num_values = ARRAY_SIZE(rk3036_defaults),
> +};
> +
> +#define RK3288_GRF_SOC_CON0		0x244
> +
> +static const struct rockchip_grf_value rk3288_defaults[] = {
> +	{ "jtag switching", RK3288_GRF_SOC_CON0, HIWORD_UPDATE(0, 1, 12) },
> +};
> +
> +static const struct rockchip_grf_info rk3288_grf = {
> +	.values = rk3288_defaults,
> +	.num_values = ARRAY_SIZE(rk3288_defaults),
> +};
> +
> +#define RK3399_GRF_SOC_CON7		0xe21c
> +
> +static const struct rockchip_grf_value rk3399_defaults[] = {
> +	{ "jtag switching", RK3399_GRF_SOC_CON7, HIWORD_UPDATE(0, 1, 12) },
> +
> +};
> +
> +static const struct rockchip_grf_info rk3399_grf = {
> +	.values = rk3399_defaults,
> +	.num_values = ARRAY_SIZE(rk3399_defaults),
> +};
> +
> +static const struct of_device_id rockchip_grf_dt_match[] = {
> +	{
> +		.compatible = "rockchip,rk3036-grf",
> +		.data = (void *)&rk3036_grf,
> +	}, {
> +		.compatible = "rockchip,rk3288-grf",
> +		.data = (void *)&rk3288_grf,
> +	}, {
> +		.compatible = "rockchip,rk3399-grf",
> +		.data = (void *)&rk3399_grf,
> +	},
> +	{ /* sentinel */ },
> +};
> +
> +static int rockchip_grf_probe(struct platform_device *pdev)
> +{
> +	const struct rockchip_grf_info *grf_info;
> +	const struct of_device_id *match;
> +	struct device *dev = &pdev->dev;
> +	struct regmap *grf;
> +	int i;
> +
> +	if (!dev->of_node)
> +		return -ENODEV;
> +
> +	match = of_match_device(rockchip_grf_dt_match, dev);
> +	if (!match || !match->data) {
> +		dev_err(dev, "missing grf data\n");
> +		return -EINVAL;
> +	}
> +
> +	grf_info = match->data;
> +
> +	grf = syscon_node_to_regmap(dev->of_node);
> +	if (IS_ERR(grf)) {
> +		dev_err(dev, "rockchip: could not get grf syscon\n");
> +		return PTR_ERR(grf);
> +	}
> +
> +	for (i = 0; i < grf_info->num_values; i++) {
> +		const struct rockchip_grf_value *val = &grf_info->values[i];
> +
> +		dev_dbg(dev, "adjusting %s in 0x%x to 0x%x\n",
> +			val->desc, val->reg, val->val);
> +		regmap_write(grf, val->reg, val->val);
> +	}
> +
> +	return 0;
> +}
> +
> +static struct platform_driver rockchip_grf_driver = {
> +	.probe = rockchip_grf_probe,
> +	.driver = {
> +		.name   = "rockchip-grf",
> +		.of_match_table = rockchip_grf_dt_match,
> +		/*
> +		 * The General Register Files are a central component
> +		 * accessed by numerous ip blocks and we're setting
> +		 * defaults which should only happen once.
> +		 */
> +		.suppress_bind_attrs = true,
> +	},
> +};
> +
> +static int __init rockchip_grf_drv_register(void)
> +{
> +	return platform_driver_register(&rockchip_grf_driver);
> +}
> +postcore_initcall(rockchip_grf_drv_register);
>


-- 
Best Regards
Shawn Lin



From zhengsq at rock-chips.com  Mon May 23 19:31:17 2016
From: zhengsq at rock-chips.com (Shunqian Zheng)
Date: Tue, 24 May 2016 10:31:17 +0800
Subject: [PATCH 4/5] iommu/rockchip: add ARM64 cache flush operation for
 iommu
In-Reply-To: <20160523133500.GF4892@e104818-lin.cambridge.arm.com>
References: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
 <1463967439-13354-5-git-send-email-zhengsq@rock-chips.com>
 <5742DEFE.1040902@arm.com>
 <20160523133500.GF4892@e104818-lin.cambridge.arm.com>
Message-ID: <5743BCF5.8030607@rock-chips.com>

Catalin, Robin,

On 2016?05?23? 21:35, Catalin Marinas wrote:
> On Mon, May 23, 2016 at 11:44:14AM +0100, Robin Murphy wrote:
>> On 23/05/16 02:37, Shunqian Zheng wrote:
>>> From: Simon <xxm at rock-chips.com>
>>>
>>> Signed-off-by: Simon <xxm at rock-chips.com>
>>> ---
>>>   drivers/iommu/rockchip-iommu.c | 4 ++++
>>>   1 file changed, 4 insertions(+)
>>>
>>> diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
>>> index 043d18c..1741b65 100644
>>> --- a/drivers/iommu/rockchip-iommu.c
>>> +++ b/drivers/iommu/rockchip-iommu.c
>>> @@ -95,12 +95,16 @@ struct rk_iommu {
>>>
>>>   static inline void rk_table_flush(u32 *va, unsigned int count)
>>>   {
>>> +#if defined(CONFIG_ARM)
>>>   	phys_addr_t pa_start = virt_to_phys(va);
>>>   	phys_addr_t pa_end = virt_to_phys(va + count);
>>>   	size_t size = pa_end - pa_start;
>>>
>>>   	__cpuc_flush_dcache_area(va, size);
>>>   	outer_flush_range(pa_start, pa_end);
>>> +#elif defined(CONFIG_ARM64)
>>> +	__dma_flush_range(va, va + count);
>>> +#endif
>> Ugh, please don't use arch-private cache maintenance functions directly from
>> a driver. Allocating/mapping page tables to be read by the IOMMU is still
>> DMA, so using the DMA APIs is the correct way to manage them, *especially*
>> if it needs to work across multiple architectures.
It's easier for us if changing  the __dma_flush_range() to 
__flush_dcache_area() is acceptable here?

Thank you,
- shunqian
> I fully agree, these functions should not be used in drivers.




From edubezval at gmail.com  Mon May 23 20:08:27 2016
From: edubezval at gmail.com (Eduardo Valentin)
Date: Mon, 23 May 2016 20:08:27 -0700
Subject: [PATCH v2 0/5] Thermal: Support for hardware-tracked trip points
In-Reply-To: <5742B217.4080405@gmail.com>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
 <5742B217.4080405@gmail.com>
Message-ID: <20160524030825.GA3489@localhost.localdomain>

On Mon, May 23, 2016 at 03:32:39PM +0800, Caesar Wang wrote:
> Hello Eduardo & 'Zhang Rui'
> 
> Do we have the chance to merge this series patches for next kernel?
> I had picked them up in my github, and tested for a period of time with
> rockchip inside kernel.
> 
> Let me know if someone have some suggestions or against opinios.
> Thanks,

I will have a look after after the current merge window.

Thanks.



From zhengxing at rock-chips.com  Mon May 23 20:47:46 2016
From: zhengxing at rock-chips.com (Xing Zheng)
Date: Tue, 24 May 2016 11:47:46 +0800
Subject: [PATCH] ASoC: rockchip: i2s: rename I2S_CKR_TRCM_TX/RXSHARE to
 I2S_CKR_TRCM_TX/RXONLY
Message-ID: <1464061667-16477-1-git-send-email-zhengxing@rock-chips.com>

From: Sugar Zhang <sugar.zhang at rock-chips.com>

this patch make it more reasonable and readable, because when we chose
I2S_CKR_TRCM_TXONLY, we only output clk_lrck_tx, and hardware need to
confirm this signal is wired to external codec lrck_tx/rx at the same time.

for convenience, we just handle lrck_txonly if we enable symmetric_rates
in driver and dai_link. otherwise, we use the separate lrck_tx/rx.

Signed-off-by: Sugar Zhang <sugar.zhang at rock-chips.com>
Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
---

 sound/soc/rockchip/rockchip_i2s.c |    4 ++--
 sound/soc/rockchip/rockchip_i2s.h |    4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index 574c6af..92a405f 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -306,8 +306,8 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
 			   I2S_DMACR_RDL(16));
 
 	val = I2S_CKR_TRCM_TXRX;
-	if (dai->driver->symmetric_rates || rtd->dai_link->symmetric_rates)
-		val = I2S_CKR_TRCM_TXSHARE;
+	if (dai->driver->symmetric_rates && rtd->dai_link->symmetric_rates)
+		val = I2S_CKR_TRCM_TXONLY;
 
 	regmap_update_bits(i2s->regmap, I2S_CKR,
 			   I2S_CKR_TRCM_MASK,
diff --git a/sound/soc/rockchip/rockchip_i2s.h b/sound/soc/rockchip/rockchip_i2s.h
index dc6e2c7..13b1d44 100644
--- a/sound/soc/rockchip/rockchip_i2s.h
+++ b/sound/soc/rockchip/rockchip_i2s.h
@@ -81,8 +81,8 @@
 #define I2S_CKR_TRCM_SHIFT	28
 #define I2S_CKR_TRCM(x)	(x << I2S_CKR_TRCM_SHIFT)
 #define I2S_CKR_TRCM_TXRX	(0 << I2S_CKR_TRCM_SHIFT)
-#define I2S_CKR_TRCM_TXSHARE	(1 << I2S_CKR_TRCM_SHIFT)
-#define I2S_CKR_TRCM_RXSHARE	(2 << I2S_CKR_TRCM_SHIFT)
+#define I2S_CKR_TRCM_TXONLY	(1 << I2S_CKR_TRCM_SHIFT)
+#define I2S_CKR_TRCM_RXONLY	(2 << I2S_CKR_TRCM_SHIFT)
 #define I2S_CKR_TRCM_MASK	(3 << I2S_CKR_TRCM_SHIFT)
 #define I2S_CKR_MSS_SHIFT	27
 #define I2S_CKR_MSS_MASTER	(0 << I2S_CKR_MSS_SHIFT)
-- 
1.7.9.5




From dianders at chromium.org  Mon May 23 21:51:19 2016
From: dianders at chromium.org (Doug Anderson)
Date: Mon, 23 May 2016 21:51:19 -0700
Subject: [PATCH 2/4] phy: rockchip-emmc: configure frequency range and
 drive impedance
In-Reply-To: <CAD=FV=UwocUy_bOUrJZB47taHWdV1KGkvi5CyZf74Y8cvGgVmw@mail.gmail.com>
References: <1463092986-61777-1-git-send-email-briannorris@chromium.org>
 <1463092986-61777-2-git-send-email-briannorris@chromium.org>
 <3695875b-09c3-cd80-3062-55d985e51f70@rock-chips.com>
 <CAD=FV=UwocUy_bOUrJZB47taHWdV1KGkvi5CyZf74Y8cvGgVmw@mail.gmail.com>
Message-ID: <CAD=FV=VYPs22rGX9Latecb0EWFA0kOCFmoSQ83wPecrFkL0m7w@mail.gmail.com>

Hi,

On Fri, May 13, 2016 at 11:46 AM, Doug Anderson <dianders at chromium.org> wrote:
>> Per the commit msg, signal may vary from board to board, so I guess
>> 50ohm may not always be the best selection?
>
> Starting out with something sane like 50 ohms seems like it makes
> sense for now.  It's OK to start with a default for now to get things
> basically working and then add device tree support once we have a
> second user.
>
>
> When we're ready to make this more generic, IMHO we might consider
> having the PHY implement the pinctrl API and officially be a pin
> controller and we use those bindings.  We are controlling pins so
> using the pinctrl API seems like it might make sense?
>
> I _think_ that perhaps what we're specifying here is actually slew
> rate, but feel free to correct me if I'm wrong.  It looks as if "drive
> strength" is supposed to be specified in terms of mA and the docs I
> find show that we're actually controlling how fast the pins will
> toggle.
>
> I'm not 100% certain I know how the pinctrl bindings apply in this
> case (maybe Heiko has ideas, or maybe we should send a proposal to
> Linus W?), but from the bindings they look like they offer some
> flexibility.
>
> Maybe this would look like below (or maybe you need some extra sub-nodes)
>
>        sdhci: sdhci at fe330000 {
>                compatible = "rockchip,rk3399-sdhci-5.1", "arasan,sdhci-5.1";
>                reg = <0x0 0xfe330000 0x0 0x10000>;
>                interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
>                clocks = <&cru SCLK_EMMC>, <&cru ACLK_EMMC>;
>                clock-names = "clk_xin", "clk_ahb";
>                assigned-clocks = <&cru SCLK_EMMC>;
>                assigned-clock-rates = <200000000>;
>                phys = <&emmc_phy>;
>                phy-names = "phy_arasan";
>                pinctrl-names = "default";
>                pinctrl-0 = <&pcfg_emmc_slew_rate_x1_00>;
>                status = "disabled";
>        };
>
>                emmc_phy: phy at f780 {
>                        compatible = "rockchip,rk3399-emmc-phy";
>                        reg = <0xf780 0x20>;
>                        #phy-cells = <0>;
>                        status = "disabled";
>
>                        pcfg_emmc_slew_rate_x1_00: pcfg-emmc-slew-rate-x1-00 {
>                                slew-rate = <100>;
>                        };
>                        pcfg_emmc_slew_rate_x1_50: pcfg-emmc-slew-rate-x1-50 {
>                                slew-rate = <150>;
>                        };
>                        pcfg_emmc_slew_rate_x0_75: pcfg-emmc-slew-rate-x0-75 {
>                                slew-rate = <75>;
>                        };
>                        pcfg_emmc_slew_rate_x0_50: pcfg-emmc-slew-rate-x0-50 {
>                                slew-rate = <50>;
>                        };
>                        pcfg_emmc_slew_rate_x1_20: pcfg-emmc-slew-rate-x1-20 {
>                                slew-rate = <120>;
>                        };
>                        pcfg_emmc_slew_rate_x1_20: pcfg-emmc-slew-rate-x1-20 {
>                                slew-rate = <120>;
>                        };
>            };
>
> The nice thing about using the pinctrl API is that:
>
> * It allows us to _also_ control pullups / pulldowns.  We probably
> want to control those also since some boards may use external pullups
> and others may want to use the internal ones.
>
> * If SDHCI needs to dynamically adjust things (like turning on pulls,
> adjusting drive strengths, etc) it can do it in a sane API.

Note that I still believe that we could land the 50 Ohm first (AKA
land the patch Brian posted), but I'm also convinced that my pinctrl
proposal above is not a good idea for the way to move forward, at
least in terms of the "driver strength" part.  Specifically it seems
like the 50 Ohm / 33 Ohm / 66 Ohm / 100 Ohm / 40 Ohm is a concept from
eMMC 5.0 and probably doesn't fit to pinctrl.

I also _think_ it needs to be matched against what's available from
the card (card->drive_strength) and the card needs to be told about
it, but I could be wrong about that.



-Doug


From ykk at rock-chips.com  Mon May 23 22:02:11 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 13:02:11 +0800
Subject: [PATCH v2 01/10] drm/bridge: analogix_dp: rename RK3288_DP to
 ROCKCHIP_DP
In-Reply-To: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464066131-22562-1-git-send-email-ykk@rock-chips.com>

Rename RK3288_DP marcos to ROCKCHIP_DP, prepare to add eDP
support for more Rockchip chips.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 4 ++--
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 6 +++---
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 2 +-
 include/drm/bridge/analogix_dp.h                   | 2 +-
 4 files changed, 7 insertions(+), 7 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 7699597..4a1b3b8 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -1207,9 +1207,9 @@ static int analogix_dp_dt_parse_pdata(struct analogix_dp_device *dp)
 	struct video_info *video_info = &dp->video_info;
 
 	switch (dp->plat_data->dev_type) {
-	case RK3288_DP:
+	case ROCKCHIP_DP:
 		/*
-		 * Like Rk3288 DisplayPort TRM indicate that "Main link
+		 * Like Rockchip DisplayPort TRM indicate that "Main link
 		 * containing 4 physical lanes of 2.7/1.62 Gbps/lane".
 		 */
 		video_info->max_link_rate = 0x0A;
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 49205ef..931a76c 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -74,7 +74,7 @@ void analogix_dp_init_analog_param(struct analogix_dp_device *dp)
 	reg = SEL_24M | TX_DVDD_BIT_1_0625V;
 	writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_2);
 
-	if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP)) {
+	if (dp->plat_data && (dp->plat_data->dev_type == ROCKCHIP_DP)) {
 		writel(REF_CLK_24M, dp->reg_base + ANALOGIX_DP_PLL_REG_1);
 		writel(0x95, dp->reg_base + ANALOGIX_DP_PLL_REG_2);
 		writel(0x40, dp->reg_base + ANALOGIX_DP_PLL_REG_3);
@@ -244,7 +244,7 @@ void analogix_dp_set_analog_power_down(struct analogix_dp_device *dp,
 	u32 reg;
 	u32 phy_pd_addr = ANALOGIX_DP_PHY_PD;
 
-	if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP))
+	if (dp->plat_data && (dp->plat_data->dev_type == ROCKCHIP_DP))
 		phy_pd_addr = ANALOGIX_DP_PD;
 
 	switch (block) {
@@ -448,7 +448,7 @@ void analogix_dp_init_aux(struct analogix_dp_device *dp)
 	analogix_dp_reset_aux(dp);
 
 	/* Disable AUX transaction H/W retry */
-	if (dp->plat_data && (dp->plat_data->dev_type == RK3288_DP))
+	if (dp->plat_data && (dp->plat_data->dev_type == ROCKCHIP_DP))
 		reg = AUX_BIT_PERIOD_EXPECTED_DELAY(0) |
 		      AUX_HW_RETRY_COUNT_SEL(3) |
 		      AUX_HW_RETRY_INTERVAL_600_MICROSECONDS;
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 7f6a55c..2bc8a7e 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -270,7 +270,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 
 	dp->plat_data.encoder = &dp->encoder;
 
-	dp->plat_data.dev_type = RK3288_DP;
+	dp->plat_data.dev_type = ROCKCHIP_DP;
 	dp->plat_data.power_on = rockchip_dp_poweron;
 	dp->plat_data.power_off = rockchip_dp_powerdown;
 
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 25afb31..9e5d013 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -15,7 +15,7 @@
 
 enum analogix_dp_devtype {
 	EXYNOS_DP,
-	RK3288_DP,
+	ROCKCHIP_DP,
 };
 
 struct analogix_dp_plat_data {
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 22:02:15 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 13:02:15 +0800
Subject: [PATCH v2 02/10] drm/rockchip: analogix_dp: split the lcdc select
 setting into device data
In-Reply-To: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464066135-22605-1-git-send-email-ykk@rock-chips.com>

eDP controller need to declare which vop provide the video source,
and it's defined in GRF registers.

But different chips have different GRF register address, so we need to
create a device data to declare the GRF messages for each chips.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
Changes in v2: None

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 35 ++++++++++++++++++-------
 1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 2bc8a7e..260c43f 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -14,6 +14,7 @@
 
 #include <linux/component.h>
 #include <linux/mfd/syscon.h>
+#include <linux/of_device.h>
 #include <linux/of_graph.h>
 #include <linux/regmap.h>
 #include <linux/reset.h>
@@ -35,11 +36,12 @@
 
 #define to_dp(nm)	container_of(nm, struct rockchip_dp_device, nm)
 
-/* dp grf register offset */
-#define GRF_SOC_CON6                            0x025c
-#define GRF_EDP_LCD_SEL_MASK                    BIT(5)
-#define GRF_EDP_SEL_VOP_LIT                     BIT(5)
-#define GRF_EDP_SEL_VOP_BIG                     0
+struct rockchip_dp_chip_data {
+	u32	lcdsel_grf_reg;
+	u32	lcdsel_big;
+	u32	lcdsel_lit;
+	u32	lcdsel_mask;
+};
 
 struct rockchip_dp_device {
 	struct drm_device        *drm_dev;
@@ -51,6 +53,8 @@ struct rockchip_dp_device {
 	struct regmap            *grf;
 	struct reset_control     *rst;
 
+	const struct rockchip_dp_chip_data *data;
+
 	struct analogix_dp_plat_data plat_data;
 };
 
@@ -119,13 +123,13 @@ static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder)
 		return;
 
 	if (ret)
-		val = GRF_EDP_SEL_VOP_LIT | (GRF_EDP_LCD_SEL_MASK << 16);
+		val = dp->data->lcdsel_lit | dp->data->lcdsel_mask;
 	else
-		val = GRF_EDP_SEL_VOP_BIG | (GRF_EDP_LCD_SEL_MASK << 16);
+		val = dp->data->lcdsel_big | dp->data->lcdsel_mask;
 
 	dev_dbg(dp->dev, "vop %s output to dp\n", (ret) ? "LIT" : "BIG");
 
-	ret = regmap_write(dp->grf, GRF_SOC_CON6, val);
+	ret = regmap_write(dp->grf, dp->data->lcdsel_grf_reg, val);
 	if (ret != 0) {
 		dev_err(dp->dev, "Could not write to GRF: %d\n", ret);
 		return;
@@ -246,6 +250,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 			    void *data)
 {
 	struct rockchip_dp_device *dp = dev_get_drvdata(dev);
+	const struct rockchip_dp_chip_data *dp_data;
 	struct drm_device *drm_dev = data;
 	int ret;
 
@@ -256,10 +261,15 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	 */
 	dev_set_drvdata(dev, NULL);
 
+	dp_data = of_device_get_match_data(dev);
+	if (!dp_data)
+		return -ENODEV;
+
 	ret = rockchip_dp_init(dp);
 	if (ret < 0)
 		return ret;
 
+	dp->data = dp_data;
 	dp->drm_dev = drm_dev;
 
 	ret = rockchip_dp_drm_create_encoder(dp);
@@ -365,8 +375,15 @@ static const struct dev_pm_ops rockchip_dp_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(rockchip_dp_suspend, rockchip_dp_resume)
 };
 
+static const struct rockchip_dp_chip_data rk3288_dp = {
+	.lcdsel_grf_reg = 0x025c,
+	.lcdsel_big = 0,
+	.lcdsel_lit = BIT(5),
+	.lcdsel_mask = BIT(21),
+};
+
 static const struct of_device_id rockchip_dp_dt_ids[] = {
-	{.compatible = "rockchip,rk3288-dp",},
+	{.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp },
 	{}
 };
 MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids);
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 22:02:19 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 13:02:19 +0800
Subject: [PATCH v2 03/10] drm/bridge: analogix_dp: correct the register bit
 define error in ANALOGIX_DP_PLL_REG_1
In-Reply-To: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464066139-22648-1-git-send-email-ykk@rock-chips.com>

There're an register define error in ANALOGIX_DP_PLL_REG_1 which introduced
by commit bcec20fd5ad6 ("drm: bridge: analogix/dp: add some rk3288 special
registers setting").

The PHY PLL input clock source is selected by ANALOGIX_DP_PLL_REG_1
BIT 0, not BIT 1.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
index 337912b..88d56ad 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
@@ -163,8 +163,8 @@
 #define HSYNC_POLARITY_CFG			(0x1 << 0)
 
 /* ANALOGIX_DP_PLL_REG_1 */
-#define REF_CLK_24M				(0x1 << 1)
-#define REF_CLK_27M				(0x0 << 1)
+#define REF_CLK_24M				(0x1 << 0)
+#define REF_CLK_27M				(0x0 << 0)
 
 /* ANALOGIX_DP_LANE_MAP */
 #define LANE3_MAP_LOGIC_LANE_0			(0x0 << 6)
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 22:02:23 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 13:02:23 +0800
Subject: [PATCH v2 04/10] drm/bridge: analogix_dp: some rockchip chips need to
 flip REF_CLK bit setting
In-Reply-To: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464066143-22691-1-git-send-email-ykk@rock-chips.com>

As vendor document indicate, when REF_CLK bit set 0, then DP
phy's REF_CLK should switch to 24M source clock.

But due to IC PHY layout mistaken, some chips need to flip this
bit(like RK3288), and unfortunately they didn't indicate in the
DP version register. That's why we have to make this little hack.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
Changes in v2:
- new patch in v2

 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c | 6 +++++-
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h | 1 +
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c   | 3 +++
 include/drm/bridge/analogix_dp.h                  | 5 +++++
 4 files changed, 14 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 931a76c..31366bf 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -75,7 +75,11 @@ void analogix_dp_init_analog_param(struct analogix_dp_device *dp)
 	writel(reg, dp->reg_base + ANALOGIX_DP_ANALOG_CTL_2);
 
 	if (dp->plat_data && (dp->plat_data->dev_type == ROCKCHIP_DP)) {
-		writel(REF_CLK_24M, dp->reg_base + ANALOGIX_DP_PLL_REG_1);
+		reg = REF_CLK_24M;
+		if (dp->plat_data->subdev_type == RK3288_DP)
+			reg = ~reg & REF_CLK_MASK;
+
+		writel(reg, dp->reg_base + ANALOGIX_DP_PLL_REG_1);
 		writel(0x95, dp->reg_base + ANALOGIX_DP_PLL_REG_2);
 		writel(0x40, dp->reg_base + ANALOGIX_DP_PLL_REG_3);
 		writel(0x58, dp->reg_base + ANALOGIX_DP_PLL_REG_4);
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
index 88d56ad..cdcc6c5 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
@@ -165,6 +165,7 @@
 /* ANALOGIX_DP_PLL_REG_1 */
 #define REF_CLK_24M				(0x1 << 0)
 #define REF_CLK_27M				(0x0 << 0)
+#define REF_CLK_MASK				(0x1 << 0)
 
 /* ANALOGIX_DP_LANE_MAP */
 #define LANE3_MAP_LOGIC_LANE_0			(0x0 << 6)
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 260c43f..29c4105 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -41,6 +41,7 @@ struct rockchip_dp_chip_data {
 	u32	lcdsel_big;
 	u32	lcdsel_lit;
 	u32	lcdsel_mask;
+	u32	chip_type;
 };
 
 struct rockchip_dp_device {
@@ -281,6 +282,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	dp->plat_data.encoder = &dp->encoder;
 
 	dp->plat_data.dev_type = ROCKCHIP_DP;
+	dp->plat_data.subdev_type = dp_data->chip_type;
 	dp->plat_data.power_on = rockchip_dp_poweron;
 	dp->plat_data.power_off = rockchip_dp_powerdown;
 
@@ -380,6 +382,7 @@ static const struct rockchip_dp_chip_data rk3288_dp = {
 	.lcdsel_big = 0,
 	.lcdsel_lit = BIT(5),
 	.lcdsel_mask = BIT(21),
+	.chip_type = RK3288_DP,
 };
 
 static const struct of_device_id rockchip_dp_dt_ids[] = {
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 9e5d013..06c0250 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -18,8 +18,13 @@ enum analogix_dp_devtype {
 	ROCKCHIP_DP,
 };
 
+enum analogix_dp_sub_devtype {
+	RK3288_DP,
+};
+
 struct analogix_dp_plat_data {
 	enum analogix_dp_devtype dev_type;
+	enum analogix_dp_sub_devtype subdev_type;
 	struct drm_panel *panel;
 	struct drm_encoder *encoder;
 	struct drm_connector *connector;
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 22:02:35 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 13:02:35 +0800
Subject: [PATCH v2 06/10] drm/rockchip: analogix_dp: make panel detect to an
 optional action
In-Reply-To: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464066155-22777-1-git-send-email-ykk@rock-chips.com>

Some boards don't need to declare a panel device node, like the
display interface is DP monitors, so it's necessary to make the
panel detect to an optional action.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
Changes in v2: None

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 48 ++++++++++++-------------
 1 file changed, 22 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index d684c97..f29ca3d 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -325,38 +325,34 @@ static int rockchip_dp_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
 	struct device_node *panel_node, *port, *endpoint;
+	struct drm_panel *panel = NULL;
 	struct rockchip_dp_device *dp;
-	struct drm_panel *panel;
 
 	port = of_graph_get_port_by_id(dev->of_node, 1);
-	if (!port) {
-		dev_err(dev, "can't find output port\n");
-		return -EINVAL;
-	}
-
-	endpoint = of_get_child_by_name(port, "endpoint");
-	of_node_put(port);
-	if (!endpoint) {
-		dev_err(dev, "no output endpoint found\n");
-		return -EINVAL;
-	}
-
-	panel_node = of_graph_get_remote_port_parent(endpoint);
-	of_node_put(endpoint);
-	if (!panel_node) {
-		dev_err(dev, "no output node found\n");
-		return -EINVAL;
-	}
-
-	panel = of_drm_find_panel(panel_node);
-	if (!panel) {
-		DRM_ERROR("failed to find panel\n");
+	if (port) {
+		endpoint = of_get_child_by_name(port, "endpoint");
+		of_node_put(port);
+		if (!endpoint) {
+			dev_err(dev, "no output endpoint found\n");
+			return -EINVAL;
+		}
+
+		panel_node = of_graph_get_remote_port_parent(endpoint);
+		of_node_put(endpoint);
+		if (!panel_node) {
+			dev_err(dev, "no output node found\n");
+			return -EINVAL;
+		}
+
+		panel = of_drm_find_panel(panel_node);
+		if (!panel) {
+			DRM_ERROR("failed to find panel\n");
+			of_node_put(panel_node);
+			return -EPROBE_DEFER;
+		}
 		of_node_put(panel_node);
-		return -EPROBE_DEFER;
 	}
 
-	of_node_put(panel_node);
-
 	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
 	if (!dp)
 		return -ENOMEM;
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 22:02:39 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 13:02:39 +0800
Subject: [PATCH v2 07/10] drm/bridge: analogix_dp: introduce connector
 mode_valid callback to plat driver
In-Reply-To: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464066159-22820-1-git-send-email-ykk@rock-chips.com>

It's helpful to expand the mode_valid callback to platform driver,
so they could valid the display mode or information.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 15 +++++++++++++++
 include/drm/bridge/analogix_dp.h                   |  4 ++++
 2 files changed, 19 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 4a1b3b8..5af9ce4 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -943,6 +943,20 @@ int analogix_dp_get_modes(struct drm_connector *connector)
 	return num_modes;
 }
 
+static enum drm_mode_status
+analogix_dp_mode_valid(struct drm_connector *connector,
+		       struct drm_display_mode *mode)
+{
+	struct analogix_dp_device *dp = to_dp(connector);
+	enum drm_mode_status status = MODE_OK;
+
+	if (dp->plat_data->mode_valid)
+		status = dp->plat_data->mode_valid(dp->plat_data, connector,
+						   mode);
+
+	return status;
+}
+
 static struct drm_encoder *
 analogix_dp_best_encoder(struct drm_connector *connector)
 {
@@ -954,6 +968,7 @@ analogix_dp_best_encoder(struct drm_connector *connector)
 static const struct drm_connector_helper_funcs analogix_dp_connector_helper_funcs = {
 	.get_modes = analogix_dp_get_modes,
 	.best_encoder = analogix_dp_best_encoder,
+	.mode_valid = analogix_dp_mode_valid,
 };
 
 enum drm_connector_status
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 82b8135..9ef89de 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -35,6 +35,10 @@ struct analogix_dp_plat_data {
 	int (*attach)(struct analogix_dp_plat_data *, struct drm_bridge *,
 		      struct drm_connector *);
 	int (*get_modes)(struct analogix_dp_plat_data *);
+
+	enum drm_mode_status (*mode_valid)(struct analogix_dp_plat_data *,
+					   struct drm_connector *,
+					   struct drm_display_mode *);
 };
 
 int analogix_dp_resume(struct device *dev);
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 22:02:44 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 13:02:44 +0800
Subject: [PATCH v2 08/10] drm/rockchip: analogix_dp: correct the connector
 display color format and bpc
In-Reply-To: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464066164-22863-1-git-send-email-ykk@rock-chips.com>

Rockchip VOP couldn't output YUV video format for eDP controller, so
when driver detect connector support YUV video format, we need to hack
it down to RGB888.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
Changes in v2: None

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index f29ca3d..910cceb 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -97,6 +97,24 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
 	return 0;
 }
 
+static enum drm_mode_status
+rockchip_dp_mode_valid(struct analogix_dp_plat_data *plat_data,
+		       struct drm_connector *connector,
+		       struct drm_display_mode *mode)
+{
+	struct drm_display_info *di = &connector->display_info;
+
+	if (di->color_formats & DRM_COLOR_FORMAT_YCRCB444 ||
+	    di->color_formats & DRM_COLOR_FORMAT_YCRCB422) {
+		di->color_formats &= ~(DRM_COLOR_FORMAT_YCRCB422 |
+				       DRM_COLOR_FORMAT_YCRCB444);
+		di->color_formats |= DRM_COLOR_FORMAT_RGB444;
+		di->bpc = 8;
+	}
+
+	return MODE_OK;
+}
+
 static bool
 rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder,
 				   const struct drm_display_mode *mode,
@@ -306,6 +324,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	dp->plat_data.subdev_type = dp_data->chip_type;
 	dp->plat_data.power_on = rockchip_dp_poweron;
 	dp->plat_data.power_off = rockchip_dp_powerdown;
+	dp->plat_data.mode_valid = rockchip_dp_mode_valid;
 
 	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
 }
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 22:02:48 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 13:02:48 +0800
Subject: [PATCH v2 09/10] drm/rockchip: analogix_dp: update the comments about
 why need to hardcode VOP output mode
In-Reply-To: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464066168-22906-1-git-send-email-ykk@rock-chips.com>

The hardware IC designed that VOP must output the RGB10 video format to
eDP contoller, and if eDP panel only support RGB8, then eDP contoller
should cut down the video data, not via VOP contoller, that's why we need
to hardcode the VOP output mode to RGA10 here.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
Changes in v2:
- new patch in v2

 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 16 +++++-----------
 1 file changed, 5 insertions(+), 11 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 910cceb..4b64964 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -170,17 +170,11 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
 	s->output_type = DRM_MODE_CONNECTOR_eDP;
 
 	/*
-	 * FIXME(Yakir): driver should configure the CRTC output video
-	 * mode with the display information which indicated the monitor
-	 * support colorimetry.
-	 *
-	 * But don't know why the CRTC driver seems could only output the
-	 * RGBaaa rightly. For example, if connect the "innolux,n116bge"
-	 * eDP screen, EDID would indicated that screen only accepted the
-	 * 6bpc mode. But if I configure CRTC to RGB666 output, then eDP
-	 * screen would show a blue picture (RGB888 show a green picture).
-	 * But if I configure CTRC to RGBaaa, and eDP driver still keep
-	 * RGB666 input video mode, then screen would works prefect.
+	 * The hardware IC designed that VOP must output the RGB10 video
+	 * format to eDP contoller, and if eDP panel only support RGB8,
+	 * then eDP contoller should cut down the video data, not via VOP
+	 * contoller, that's why we need to hardcode the VOP output mode
+	 * to RGA10 here.
 	 */
 
 	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 22:02:52 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 13:02:52 +0800
Subject: [PATCH v2 10/10] drm/bridge: analogix_dp: fix no drm hpd event when
 panel plug in
In-Reply-To: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464066172-22949-1-git-send-email-ykk@rock-chips.com>

The enum value of DP_IRQ_TYPE_HP_CABLE_IN is zero, but driver only
send drm hp event when the irq_type and the enum value is true.

if (irq_type & DP_IRQ_TYPE_HP_CABLE_IN || ...)
	drm_helper_hpd_irq_event(dp->drm_dev);

So there would no drm hpd event when cable plug in, to fix that
just need to assign all hotplug enum with no-zero values.

Reported-by: Dan Carpenter <dan.carpenter at oracle.com>
Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
Changes in v2: None

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index f09275d..b456380 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -127,10 +127,10 @@ enum analog_power_block {
 };
 
 enum dp_irq_type {
-	DP_IRQ_TYPE_HP_CABLE_IN,
-	DP_IRQ_TYPE_HP_CABLE_OUT,
-	DP_IRQ_TYPE_HP_CHANGE,
-	DP_IRQ_TYPE_UNKNOWN,
+	DP_IRQ_TYPE_HP_CABLE_IN  = BIT(0),
+	DP_IRQ_TYPE_HP_CABLE_OUT = BIT(1),
+	DP_IRQ_TYPE_HP_CHANGE    = BIT(2),
+	DP_IRQ_TYPE_UNKNOWN      = BIT(3),
 };
 
 struct video_info {
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 22:01:26 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 13:01:26 +0800
Subject: [PATCH v2 0/10] Add RK3399 eDP support and fix some bugs to
 analogix_dp driver.
Message-ID: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>


Hi all,

This series have been posted about one month, still no comments, help here :(

RK3399 and RK3288 shared the same eDP IP controller, only some light
difference with VOP configure and GRF configure.

Also same misc fix to analogix_dp driver:
- Hotplug invalid which report by Dan Carpenter
- Make panel detect to an optional action
- correct the register bit define error in ANALOGIX_DP_PLL_REG_1


Changes in v2:
- new patch in v2
- rebase with drm-next, fix some conflicts
- new patch in v2

Yakir Yang (10):
  drm/bridge: analogix_dp: rename RK3288_DP to ROCKCHIP_DP
  drm/rockchip: analogix_dp: split the lcdc select setting into device
    data
  drm/bridge: analogix_dp: correct the register bit define error in
    ANALOGIX_DP_PLL_REG_1
  drm/bridge: analogix_dp: some rockchip chips need to flip REF_CLK bit
    setting
  drm/rockchip: analogix_dp: add rk3399 eDP support
  drm/rockchip: analogix_dp: make panel detect to an optional action
  drm/bridge: analogix_dp: introduce connector mode_valid callback to
    plat driver
  drm/rockchip: analogix_dp: correct the connector display color format
    and bpc
  drm/rockchip: analogix_dp: update the comments about why need to
    hardcode VOP output mode
  drm/bridge: analogix_dp: fix no drm hpd event when panel plug in

 .../bindings/display/bridge/analogix_dp.txt        |   1 +
 .../display/rockchip/analogix_dp-rockchip.txt      |   2 +-
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  19 ++-
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |   8 +-
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  |  12 +-
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  |   5 +-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 157 ++++++++++++++-------
 include/drm/bridge/analogix_dp.h                   |  10 ++
 8 files changed, 152 insertions(+), 62 deletions(-)

-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 22:02:27 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 13:02:27 +0800
Subject: [PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
In-Reply-To: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464066147-22734-1-git-send-email-ykk@rock-chips.com>

RK3399 and RK3288 shared the same eDP IP controller, only some light
difference with VOP configure and GRF configure.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
Changes in v2:
- rebase with drm-next, fix some conflicts

 .../bindings/display/bridge/analogix_dp.txt        |  1 +
 .../display/rockchip/analogix_dp-rockchip.txt      |  2 +-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 34 ++++++++++++++++++++--
 include/drm/bridge/analogix_dp.h                   |  1 +
 4 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
index 4f2ba8c..4a0f4f7 100644
--- a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
+++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
@@ -5,6 +5,7 @@ Required properties for dp-controller:
 		platform specific such as:
 		 * "samsung,exynos5-dp"
 		 * "rockchip,rk3288-dp"
+		 * "rockchip,rk3399-edp"
 	-reg:
 		physical base address of the controller and length
 		of memory mapped region.
diff --git a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt
index e832ff9..5ae55ca 100644
--- a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt
@@ -2,7 +2,7 @@ Rockchip RK3288 specific extensions to the Analogix Display Port
 ================================
 
 Required properties:
-- compatible: "rockchip,rk3288-edp";
+- compatible: "rockchip,rk3288-edp" or "rockchip,rk3399-edp";
 
 - reg: physical base address of the controller and length
 
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 29c4105..d684c97 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -149,6 +149,8 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
 {
 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
 
+	s->output_type = DRM_MODE_CONNECTOR_eDP;
+
 	/*
 	 * FIXME(Yakir): driver should configure the CRTC output video
 	 * mode with the display information which indicated the monitor
@@ -162,8 +164,27 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
 	 * But if I configure CTRC to RGBaaa, and eDP driver still keep
 	 * RGB666 input video mode, then screen would works prefect.
 	 */
-	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
-	s->output_type = DRM_MODE_CONNECTOR_eDP;
+
+	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
+	if (ret < 0)
+		return;
+
+	switch (dp->data->chip_type) {
+	case RK3399_EDP:
+		/*
+		 * For RK3399, VOP Lit must code the out mode to RGB888,
+		 * VOP Big must code the out mode to RGB10.
+		 */
+		if (ret)
+			s->output_mode = ROCKCHIP_OUT_MODE_P888;
+		else
+			s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
+		break;
+
+	default:
+		s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
+		break;
+	}
 
 	return 0;
 }
@@ -377,6 +398,14 @@ static const struct dev_pm_ops rockchip_dp_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(rockchip_dp_suspend, rockchip_dp_resume)
 };
 
+static const struct rockchip_dp_chip_data rk3399_edp = {
+	.lcdsel_grf_reg = 0x6250,
+	.lcdsel_big = 0,
+	.lcdsel_lit = BIT(5),
+	.lcdsel_mask = BIT(21),
+	.chip_type = RK3399_EDP,
+};
+
 static const struct rockchip_dp_chip_data rk3288_dp = {
 	.lcdsel_grf_reg = 0x025c,
 	.lcdsel_big = 0,
@@ -387,6 +416,7 @@ static const struct rockchip_dp_chip_data rk3288_dp = {
 
 static const struct of_device_id rockchip_dp_dt_ids[] = {
 	{.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp },
+	{.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp },
 	{}
 };
 MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids);
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 06c0250..82b8135 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -20,6 +20,7 @@ enum analogix_dp_devtype {
 
 enum analogix_dp_sub_devtype {
 	RK3288_DP,
+	RK3399_EDP,
 };
 
 struct analogix_dp_plat_data {
-- 
1.9.1




From ykk at rock-chips.com  Mon May 23 23:57:23 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 24 May 2016 14:57:23 +0800
Subject: [PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
In-Reply-To: <1464066147-22734-1-git-send-email-ykk@rock-chips.com>
References: <1464066147-22734-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464073043-4931-1-git-send-email-ykk@rock-chips.com>

RK3399 and RK3288 shared the same eDP IP controller, only some light
difference with VOP configure and GRF configure.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
Changes in v2:
- rebase with drm-next, fix some conflicts

 .../bindings/display/bridge/analogix_dp.txt        |  1 +
 .../display/rockchip/analogix_dp-rockchip.txt      |  2 +-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 36 ++++++++++++++++++++--
 include/drm/bridge/analogix_dp.h                   |  1 +
 4 files changed, 37 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
index 4f2ba8c..4a0f4f7 100644
--- a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
+++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
@@ -5,6 +5,7 @@ Required properties for dp-controller:
 		platform specific such as:
 		 * "samsung,exynos5-dp"
 		 * "rockchip,rk3288-dp"
+		 * "rockchip,rk3399-edp"
 	-reg:
 		physical base address of the controller and length
 		of memory mapped region.
diff --git a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt
index e832ff9..5ae55ca 100644
--- a/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt
+++ b/Documentation/devicetree/bindings/display/rockchip/analogix_dp-rockchip.txt
@@ -2,7 +2,7 @@ Rockchip RK3288 specific extensions to the Analogix Display Port
 ================================
 
 Required properties:
-- compatible: "rockchip,rk3288-edp";
+- compatible: "rockchip,rk3288-edp" or "rockchip,rk3399-edp";
 
 - reg: physical base address of the controller and length
 
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index 29c4105..d5d4e04 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -148,6 +148,10 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
 				      struct drm_connector_state *conn_state)
 {
 	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+	struct rockchip_dp_device *dp = to_dp(encoder);
+	int ret;
+
+	s->output_type = DRM_MODE_CONNECTOR_eDP;
 
 	/*
 	 * FIXME(Yakir): driver should configure the CRTC output video
@@ -162,8 +166,27 @@ rockchip_dp_drm_encoder_atomic_check(struct drm_encoder *encoder,
 	 * But if I configure CTRC to RGBaaa, and eDP driver still keep
 	 * RGB666 input video mode, then screen would works prefect.
 	 */
-	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
-	s->output_type = DRM_MODE_CONNECTOR_eDP;
+
+	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
+	if (ret < 0)
+		return;
+
+	switch (dp->data->chip_type) {
+	case RK3399_EDP:
+		/*
+		 * For RK3399, VOP Lit must code the out mode to RGB888,
+		 * VOP Big must code the out mode to RGB10.
+		 */
+		if (ret)
+			s->output_mode = ROCKCHIP_OUT_MODE_P888;
+		else
+			s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
+		break;
+
+	default:
+		s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
+		break;
+	}
 
 	return 0;
 }
@@ -377,6 +400,14 @@ static const struct dev_pm_ops rockchip_dp_pm_ops = {
 	SET_SYSTEM_SLEEP_PM_OPS(rockchip_dp_suspend, rockchip_dp_resume)
 };
 
+static const struct rockchip_dp_chip_data rk3399_edp = {
+	.lcdsel_grf_reg = 0x6250,
+	.lcdsel_big = 0,
+	.lcdsel_lit = BIT(5),
+	.lcdsel_mask = BIT(21),
+	.chip_type = RK3399_EDP,
+};
+
 static const struct rockchip_dp_chip_data rk3288_dp = {
 	.lcdsel_grf_reg = 0x025c,
 	.lcdsel_big = 0,
@@ -387,6 +418,7 @@ static const struct rockchip_dp_chip_data rk3288_dp = {
 
 static const struct of_device_id rockchip_dp_dt_ids[] = {
 	{.compatible = "rockchip,rk3288-dp", .data = &rk3288_dp },
+	{.compatible = "rockchip,rk3399-edp", .data = &rk3399_edp },
 	{}
 };
 MODULE_DEVICE_TABLE(of, rockchip_dp_dt_ids);
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 06c0250..82b8135 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -20,6 +20,7 @@ enum analogix_dp_devtype {
 
 enum analogix_dp_sub_devtype {
 	RK3288_DP,
+	RK3399_EDP,
 };
 
 struct analogix_dp_plat_data {
-- 
1.9.1




From daniel at fooishbar.org  Tue May 24 00:19:10 2016
From: daniel at fooishbar.org (Daniel Stone)
Date: Tue, 24 May 2016 09:19:10 +0200
Subject: [PATCH] drm/rockchip: Return -EBUSY if there's already a pending
 flip event v3
In-Reply-To: <CAAObsKAyeg9JsPhCyWqLpg3n6V9Ab8OCJKXX41A86rQWWs+SdQ@mail.gmail.com>
References: <1459778134-30693-1-git-send-email-tomeu.vizoso@collabora.com>
 <CAPj87rPtP1ph-1FMxSKUANjeKwwjwgfMzbUGHvqudEx7nYCESQ@mail.gmail.com>
 <CAAObsKAyeg9JsPhCyWqLpg3n6V9Ab8OCJKXX41A86rQWWs+SdQ@mail.gmail.com>
Message-ID: <CAPj87rPgvjs5W68Cou6ODDqbqbPXQvFxLPtegBkdxdtPaRMX7A@mail.gmail.com>

Hi Tomeu,

On 5 April 2016 at 16:07, Tomeu Vizoso <tomeu.vizoso at collabora.com> wrote:
> On 4 April 2016 at 17:44, Daniel Stone <daniel at fooishbar.org> wrote:
>> On 4 April 2016 at 14:55, Tomeu Vizoso <tomeu.vizoso at collabora.com> wrote:
>>> +       if (async) {
>>> +               for_each_crtc_in_state(state, crtc, crtc_state, i) {
>>> +                       if (crtc->state->event ||
>>> +                           rockchip_drm_crtc_has_pending_event(crtc)) {
>>> +                               return -EBUSY;
>>> +                       }
>>> +               }
>>> +       }
>>
>> Hmmm ...
>>
>> Doesn't this trigger before the VOP atomic_begin() helper, meaning
>> that anything with an event set will trigger the check? Seems like it
>> should be && rather than ||.
>
> So, these are the two cases that this code aims to handle:
>
> 1. A previous request with an event set hasn't progressed to
> atomic_begin yet, so the event field in drm_crtc_state (at this point,
> the old state) is still populated but vop->event still isn't.

Ah right, this was what I was missing: the async (non-blocking)
implementation. Sounds good to me then.

Cheers,
Daniel


From tomeu.vizoso at collabora.com  Tue May 24 00:26:01 2016
From: tomeu.vizoso at collabora.com (Tomeu Vizoso)
Date: Tue, 24 May 2016 09:26:01 +0200
Subject: [PATCH] drm/rockchip: Return -EBUSY if there's already a pending flip
 event v4
Message-ID: <1464074761-5194-1-git-send-email-tomeu.vizoso@collabora.com>

As per the docs, atomic_commit should return -EBUSY "if an asycnhronous
updated is requested and there is an earlier updated pending".

v2: Use the status of the workqueue instead of vop->event, and don't add
a superfluous wait on the workqueue.

v3: Drop work_busy, as there's a sizeable delay when the worker
finishes, which introduces a race in which the client has already
received the last flip event but the next page flip ioctl will still
return -EBUSY because work_busy returns outdated information.

v4: Hold dev->event_lock while checking the VOP's event field as
suggested by Daniel Stone.

v5: Only block if there's outstanding work if it's a blocking call.

Signed-off-by: Tomeu Vizoso <tomeu.vizoso at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |  1 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  | 25 ++++++++++++++++++++++---
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  6 ++++++
 3 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 56f43a364c7f..0b46617decd9 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -76,6 +76,7 @@ void rockchip_drm_atomic_work(struct work_struct *work);
 int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
 				 const struct rockchip_crtc_funcs *crtc_funcs);
 void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc);
+bool rockchip_drm_crtc_has_pending_event(struct drm_crtc *crtc);
 int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
 				   struct device *dev);
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 755cfdba61cd..e9531353b8d2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -279,15 +279,34 @@ int rockchip_drm_atomic_commit(struct drm_device *dev,
 {
 	struct rockchip_drm_private *private = dev->dev_private;
 	struct rockchip_atomic_commit *commit = &private->commit;
-	int ret;
+	struct drm_crtc_state *crtc_state;
+	struct drm_crtc *crtc;
+	unsigned long flags;
+	int i, ret;
+
+	if (nonblock) {
+		for_each_crtc_in_state(state, crtc, crtc_state, i) {
+			spin_lock_irqsave(&dev->event_lock, flags);
+
+			if (crtc->state->event ||
+			    rockchip_drm_crtc_has_pending_event(crtc)) {
+				spin_unlock_irqrestore(&dev->event_lock, flags);
+				return -EBUSY;
+			}
+
+			spin_unlock_irqrestore(&dev->event_lock, flags);
+		}
+	}
 
 	ret = drm_atomic_helper_prepare_planes(dev, state);
 	if (ret)
 		return ret;
 
-	/* serialize outstanding nonblocking commits */
 	mutex_lock(&commit->lock);
-	flush_work(&commit->work);
+
+	/* serialize outstanding nonblocking commits */
+	if (!nonblock)
+		flush_work(&commit->work);
 
 	drm_atomic_helper_swap_state(dev, state);
 
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 1c4d5b5a70a2..3f980f52c640 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -836,6 +836,12 @@ static const struct drm_plane_funcs vop_plane_funcs = {
 	.atomic_destroy_state = vop_atomic_plane_destroy_state,
 };
 
+bool rockchip_drm_crtc_has_pending_event(struct drm_crtc *crtc)
+{
+	assert_spin_locked(&crtc->dev->event_lock);
+	return to_vop(crtc)->event;
+}
+
 static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
 {
 	struct vop *vop = to_vop(crtc);
-- 
2.5.5



From tomeu.vizoso at collabora.com  Tue May 24 00:27:37 2016
From: tomeu.vizoso at collabora.com (Tomeu Vizoso)
Date: Tue, 24 May 2016 09:27:37 +0200
Subject: [PATCH] drm/rockchip: Return -EBUSY if there's already a pending flip
 event v5
In-Reply-To: <1464074761-5194-1-git-send-email-tomeu.vizoso@collabora.com>
References: <1464074761-5194-1-git-send-email-tomeu.vizoso@collabora.com>
Message-ID: <1464074857-5515-1-git-send-email-tomeu.vizoso@collabora.com>

As per the docs, atomic_commit should return -EBUSY "if an asycnhronous
updated is requested and there is an earlier updated pending".

v2: Use the status of the workqueue instead of vop->event, and don't add
a superfluous wait on the workqueue.

v3: Drop work_busy, as there's a sizeable delay when the worker
finishes, which introduces a race in which the client has already
received the last flip event but the next page flip ioctl will still
return -EBUSY because work_busy returns outdated information.

v4: Hold dev->event_lock while checking the VOP's event field as
suggested by Daniel Stone.

v5: Only block if there's outstanding work if it's a blocking call.

Signed-off-by: Tomeu Vizoso <tomeu.vizoso at collabora.com>
---
 drivers/gpu/drm/rockchip/rockchip_drm_drv.h |  1 +
 drivers/gpu/drm/rockchip/rockchip_drm_fb.c  | 25 ++++++++++++++++++++++---
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c |  6 ++++++
 3 files changed, 29 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
index 56f43a364c7f..0b46617decd9 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.h
@@ -76,6 +76,7 @@ void rockchip_drm_atomic_work(struct work_struct *work);
 int rockchip_register_crtc_funcs(struct drm_crtc *crtc,
 				 const struct rockchip_crtc_funcs *crtc_funcs);
 void rockchip_unregister_crtc_funcs(struct drm_crtc *crtc);
+bool rockchip_drm_crtc_has_pending_event(struct drm_crtc *crtc);
 int rockchip_drm_dma_attach_device(struct drm_device *drm_dev,
 				   struct device *dev);
 void rockchip_drm_dma_detach_device(struct drm_device *drm_dev,
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
index 755cfdba61cd..e9531353b8d2 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_fb.c
@@ -279,15 +279,34 @@ int rockchip_drm_atomic_commit(struct drm_device *dev,
 {
 	struct rockchip_drm_private *private = dev->dev_private;
 	struct rockchip_atomic_commit *commit = &private->commit;
-	int ret;
+	struct drm_crtc_state *crtc_state;
+	struct drm_crtc *crtc;
+	unsigned long flags;
+	int i, ret;
+
+	if (nonblock) {
+		for_each_crtc_in_state(state, crtc, crtc_state, i) {
+			spin_lock_irqsave(&dev->event_lock, flags);
+
+			if (crtc->state->event ||
+			    rockchip_drm_crtc_has_pending_event(crtc)) {
+				spin_unlock_irqrestore(&dev->event_lock, flags);
+				return -EBUSY;
+			}
+
+			spin_unlock_irqrestore(&dev->event_lock, flags);
+		}
+	}
 
 	ret = drm_atomic_helper_prepare_planes(dev, state);
 	if (ret)
 		return ret;
 
-	/* serialize outstanding nonblocking commits */
 	mutex_lock(&commit->lock);
-	flush_work(&commit->work);
+
+	/* serialize outstanding nonblocking commits */
+	if (!nonblock)
+		flush_work(&commit->work);
 
 	drm_atomic_helper_swap_state(dev, state);
 
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 1c4d5b5a70a2..3f980f52c640 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -836,6 +836,12 @@ static const struct drm_plane_funcs vop_plane_funcs = {
 	.atomic_destroy_state = vop_atomic_plane_destroy_state,
 };
 
+bool rockchip_drm_crtc_has_pending_event(struct drm_crtc *crtc)
+{
+	assert_spin_locked(&crtc->dev->event_lock);
+	return to_vop(crtc)->event;
+}
+
 static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
 {
 	struct vop *vop = to_vop(crtc);
-- 
2.5.5



From daniel at fooishbar.org  Tue May 24 00:34:50 2016
From: daniel at fooishbar.org (Daniel Stone)
Date: Tue, 24 May 2016 09:34:50 +0200
Subject: [PATCH] drm/rockchip: Return -EBUSY if there's already a pending
 flip event v5
In-Reply-To: <1464074857-5515-1-git-send-email-tomeu.vizoso@collabora.com>
References: <1464074761-5194-1-git-send-email-tomeu.vizoso@collabora.com>
 <1464074857-5515-1-git-send-email-tomeu.vizoso@collabora.com>
Message-ID: <CAPj87rPfakpstxmK3rodunVp2aX-gkLqoqQJ+gfoazaH0ej29g@mail.gmail.com>

On 24 May 2016 at 09:27, Tomeu Vizoso <tomeu.vizoso at collabora.com> wrote:
> As per the docs, atomic_commit should return -EBUSY "if an asycnhronous
> updated is requested and there is an earlier updated pending".
>
> v2: Use the status of the workqueue instead of vop->event, and don't add
> a superfluous wait on the workqueue.
>
> v3: Drop work_busy, as there's a sizeable delay when the worker
> finishes, which introduces a race in which the client has already
> received the last flip event but the next page flip ioctl will still
> return -EBUSY because work_busy returns outdated information.
>
> v4: Hold dev->event_lock while checking the VOP's event field as
> suggested by Daniel Stone.
>
> v5: Only block if there's outstanding work if it's a blocking call.
>
> Signed-off-by: Tomeu Vizoso <tomeu.vizoso at collabora.com>

Reviewed-by: Daniel Stone <daniels at collabora.com>

Cheers,
Daniel


From heiko at sntech.de  Tue May 24 01:28:42 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 24 May 2016 10:28:42 +0200
Subject: [PATCH] drm/rockchip: Return -EBUSY if there's already a pending
 flip event v5
In-Reply-To: <1464074857-5515-1-git-send-email-tomeu.vizoso@collabora.com>
References: <1464074761-5194-1-git-send-email-tomeu.vizoso@collabora.com>
 <1464074857-5515-1-git-send-email-tomeu.vizoso@collabora.com>
Message-ID: <7363560.k3ytHeYgtM@phil>

Hi Tomeu,

Patch subject: please put the version into the brackets, so [PATCH v5] as it 
shouldn't be part of the commit log.

Am Dienstag, 24. Mai 2016, 09:27:37 schrieb Tomeu Vizoso:
> As per the docs, atomic_commit should return -EBUSY "if an asycnhronous
> updated is requested and there is an earlier updated pending".

> v2: Use the status of the workqueue instead of vop->event, and don't add
> a superfluous wait on the workqueue.
> 
> v3: Drop work_busy, as there's a sizeable delay when the worker
> finishes, which introduces a race in which the client has already
> received the last flip event but the next page flip ioctl will still
> return -EBUSY because work_busy returns outdated information.
> 
> v4: Hold dev->event_lock while checking the VOP's event field as
> suggested by Daniel Stone.
> 
> v5: Only block if there's outstanding work if it's a blocking call.

similarly, please put the changelog below the "---" and above the diffstat.


> Signed-off-by: Tomeu Vizoso <tomeu.vizoso at collabora.com>
> ---

aka here.

>  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |  1 +
>  drivers/gpu/drm/rockchip/rockchip_drm_fb.c  | 25
> ++++++++++++++++++++++--- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 
> 6 ++++++
>  3 files changed, 29 insertions(+), 3 deletions(-)

Heiko


From daniel at ffwll.ch  Tue May 24 01:30:50 2016
From: daniel at ffwll.ch (Daniel Vetter)
Date: Tue, 24 May 2016 10:30:50 +0200
Subject: [PATCH] drm/rockchip: Return -EBUSY if there's already a pending
 flip event v5
In-Reply-To: <7363560.k3ytHeYgtM@phil>
References: <1464074761-5194-1-git-send-email-tomeu.vizoso@collabora.com>
 <1464074857-5515-1-git-send-email-tomeu.vizoso@collabora.com>
 <7363560.k3ytHeYgtM@phil>
Message-ID: <20160524083050.GQ27098@phenom.ffwll.local>

On Tue, May 24, 2016 at 10:28:42AM +0200, Heiko Stuebner wrote:
> Hi Tomeu,
> 
> Patch subject: please put the version into the brackets, so [PATCH v5] as it 
> shouldn't be part of the commit log.
> 
> Am Dienstag, 24. Mai 2016, 09:27:37 schrieb Tomeu Vizoso:
> > As per the docs, atomic_commit should return -EBUSY "if an asycnhronous
> > updated is requested and there is an earlier updated pending".
> 
> > v2: Use the status of the workqueue instead of vop->event, and don't add
> > a superfluous wait on the workqueue.
> > 
> > v3: Drop work_busy, as there's a sizeable delay when the worker
> > finishes, which introduces a race in which the client has already
> > received the last flip event but the next page flip ioctl will still
> > return -EBUSY because work_busy returns outdated information.
> > 
> > v4: Hold dev->event_lock while checking the VOP's event field as
> > suggested by Daniel Stone.
> > 
> > v5: Only block if there's outstanding work if it's a blocking call.
> 
> similarly, please put the changelog below the "---" and above the diffstat.

drm culture is to keep it above, since it's kinda useful sometimes when
later on trying to reconstruct wtf was discussed and why a patch was
merged.
-Daniel

> 
> 
> > Signed-off-by: Tomeu Vizoso <tomeu.vizoso at collabora.com>
> > ---
> 
> aka here.
> 
> >  drivers/gpu/drm/rockchip/rockchip_drm_drv.h |  1 +
> >  drivers/gpu/drm/rockchip/rockchip_drm_fb.c  | 25
> > ++++++++++++++++++++++--- drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 
> > 6 ++++++
> >  3 files changed, 29 insertions(+), 3 deletions(-)
> 
> Heiko
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


From daniel at ffwll.ch  Tue May 24 01:37:49 2016
From: daniel at ffwll.ch (Daniel Vetter)
Date: Tue, 24 May 2016 10:37:49 +0200
Subject: [PATCH] drm/rockchip: Return -EBUSY if there's already a pending
 flip event v5
In-Reply-To: <20160524083050.GQ27098@phenom.ffwll.local>
References: <1464074761-5194-1-git-send-email-tomeu.vizoso@collabora.com>
 <1464074857-5515-1-git-send-email-tomeu.vizoso@collabora.com>
 <7363560.k3ytHeYgtM@phil>
 <20160524083050.GQ27098@phenom.ffwll.local>
Message-ID: <20160524083749.GR27098@phenom.ffwll.local>

On Tue, May 24, 2016 at 10:30:50AM +0200, Daniel Vetter wrote:
> On Tue, May 24, 2016 at 10:28:42AM +0200, Heiko Stuebner wrote:
> > Hi Tomeu,
> > 
> > Patch subject: please put the version into the brackets, so [PATCH v5] as it 
> > shouldn't be part of the commit log.
> > 
> > Am Dienstag, 24. Mai 2016, 09:27:37 schrieb Tomeu Vizoso:
> > > As per the docs, atomic_commit should return -EBUSY "if an asycnhronous
> > > updated is requested and there is an earlier updated pending".
> > 
> > > v2: Use the status of the workqueue instead of vop->event, and don't add
> > > a superfluous wait on the workqueue.
> > > 
> > > v3: Drop work_busy, as there's a sizeable delay when the worker
> > > finishes, which introduces a race in which the client has already
> > > received the last flip event but the next page flip ioctl will still
> > > return -EBUSY because work_busy returns outdated information.
> > > 
> > > v4: Hold dev->event_lock while checking the VOP's event field as
> > > suggested by Daniel Stone.
> > > 
> > > v5: Only block if there's outstanding work if it's a blocking call.
> > 
> > similarly, please put the changelog below the "---" and above the diffstat.
> 
> drm culture is to keep it above, since it's kinda useful sometimes when
> later on trying to reconstruct wtf was discussed and why a patch was
> merged.

Maybe needs a bit more context: The only stuff you raised in your review
is tiny style nits of pretty much utter irrelevance. No substantial and
material feedback anywehere, and in my opinion in such a case either fix
up the nits when applying (when you feel really strongly about perfect
patches), or just merge as-is.

But sending out content-less bikesheds like these just adds noise and
helps no-one. I think at least some spelling stuff is the minimal bar (but
then just include your r-b tag), but personally I don't even care about
that so much, as long as it's still legible.

Thanks, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


From heiko at sntech.de  Tue May 24 01:41:30 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 24 May 2016 10:41:30 +0200
Subject: [PATCH] drm/rockchip: Return -EBUSY if there's already a pending
 flip event v5
In-Reply-To: <20160524083749.GR27098@phenom.ffwll.local>
References: <1464074761-5194-1-git-send-email-tomeu.vizoso@collabora.com>
 <20160524083050.GQ27098@phenom.ffwll.local>
 <20160524083749.GR27098@phenom.ffwll.local>
Message-ID: <1885816.5oayNdNrp7@phil>

Am Dienstag, 24. Mai 2016, 10:37:49 schrieb Daniel Vetter:
> On Tue, May 24, 2016 at 10:30:50AM +0200, Daniel Vetter wrote:
> > On Tue, May 24, 2016 at 10:28:42AM +0200, Heiko Stuebner wrote:
> > > Hi Tomeu,
> > > 
> > > Patch subject: please put the version into the brackets, so [PATCH v5]
> > > as it shouldn't be part of the commit log.
> > > 
> > > Am Dienstag, 24. Mai 2016, 09:27:37 schrieb Tomeu Vizoso:
> > > > As per the docs, atomic_commit should return -EBUSY "if an
> > > > asycnhronous
> > > > updated is requested and there is an earlier updated pending".
> > > > 
> > > > v2: Use the status of the workqueue instead of vop->event, and don't
> > > > add
> > > > a superfluous wait on the workqueue.
> > > > 
> > > > v3: Drop work_busy, as there's a sizeable delay when the worker
> > > > finishes, which introduces a race in which the client has already
> > > > received the last flip event but the next page flip ioctl will still
> > > > return -EBUSY because work_busy returns outdated information.
> > > > 
> > > > v4: Hold dev->event_lock while checking the VOP's event field as
> > > > suggested by Daniel Stone.
> > > > 
> > > > v5: Only block if there's outstanding work if it's a blocking call.
> > > 
> > > similarly, please put the changelog below the "---" and above the
> > > diffstat.> 
> > drm culture is to keep it above, since it's kinda useful sometimes when
> > later on trying to reconstruct wtf was discussed and why a patch was
> > merged.
> 
> Maybe needs a bit more context: The only stuff you raised in your review
> is tiny style nits of pretty much utter irrelevance. No substantial and
> material feedback anywehere, and in my opinion in such a case either fix
> up the nits when applying (when you feel really strongly about perfect
> patches), or just merge as-is.
> 
> But sending out content-less bikesheds like these just adds noise and
> helps no-one. I think at least some spelling stuff is the minimal bar (but
> then just include your r-b tag), but personally I don't even care about
> that so much, as long as it's still legible.

ok, will keep that (both mails) in mind for future stuff.

Heiko


From daniel at ffwll.ch  Tue May 24 02:03:20 2016
From: daniel at ffwll.ch (Daniel Vetter)
Date: Tue, 24 May 2016 11:03:20 +0200
Subject: [PATCH] drm/rockchip: Return -EBUSY if there's already a pending
 flip event v5
In-Reply-To: <1885816.5oayNdNrp7@phil>
References: <1464074761-5194-1-git-send-email-tomeu.vizoso@collabora.com>
 <20160524083050.GQ27098@phenom.ffwll.local>
 <20160524083749.GR27098@phenom.ffwll.local>
 <1885816.5oayNdNrp7@phil>
Message-ID: <20160524090320.GS27098@phenom.ffwll.local>

On Tue, May 24, 2016 at 10:41:30AM +0200, Heiko Stuebner wrote:
> Am Dienstag, 24. Mai 2016, 10:37:49 schrieb Daniel Vetter:
> > On Tue, May 24, 2016 at 10:30:50AM +0200, Daniel Vetter wrote:
> > > On Tue, May 24, 2016 at 10:28:42AM +0200, Heiko Stuebner wrote:
> > > > Hi Tomeu,
> > > > 
> > > > Patch subject: please put the version into the brackets, so [PATCH v5]
> > > > as it shouldn't be part of the commit log.
> > > > 
> > > > Am Dienstag, 24. Mai 2016, 09:27:37 schrieb Tomeu Vizoso:
> > > > > As per the docs, atomic_commit should return -EBUSY "if an
> > > > > asycnhronous
> > > > > updated is requested and there is an earlier updated pending".
> > > > > 
> > > > > v2: Use the status of the workqueue instead of vop->event, and don't
> > > > > add
> > > > > a superfluous wait on the workqueue.
> > > > > 
> > > > > v3: Drop work_busy, as there's a sizeable delay when the worker
> > > > > finishes, which introduces a race in which the client has already
> > > > > received the last flip event but the next page flip ioctl will still
> > > > > return -EBUSY because work_busy returns outdated information.
> > > > > 
> > > > > v4: Hold dev->event_lock while checking the VOP's event field as
> > > > > suggested by Daniel Stone.
> > > > > 
> > > > > v5: Only block if there's outstanding work if it's a blocking call.
> > > > 
> > > > similarly, please put the changelog below the "---" and above the
> > > > diffstat.> 
> > > drm culture is to keep it above, since it's kinda useful sometimes when
> > > later on trying to reconstruct wtf was discussed and why a patch was
> > > merged.
> > 
> > Maybe needs a bit more context: The only stuff you raised in your review
> > is tiny style nits of pretty much utter irrelevance. No substantial and
> > material feedback anywehere, and in my opinion in such a case either fix
> > up the nits when applying (when you feel really strongly about perfect
> > patches), or just merge as-is.
> > 
> > But sending out content-less bikesheds like these just adds noise and
> > helps no-one. I think at least some spelling stuff is the minimal bar (but
> > then just include your r-b tag), but personally I don't even care about
> > that so much, as long as it's still legible.
> 
> ok, will keep that (both mails) in mind for future stuff.

And to clarify, review of patches is very much appreciated, but to be
effective it should be top down. First assess whether it's a good idea,
then whether the implementation makes sense, then go down into style
naming and details like that. And it's important to tell the submitter
where they are in that process, too. More in-depth writeup of a good
review approach:

http://sarah.thesharps.us/2014/09/01/the-gentle-art-of-patch-review/

Cheers, Daniel
-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


From balbi at kernel.org  Tue May 24 02:32:23 2016
From: balbi at kernel.org (Felipe Balbi)
Date: Tue, 24 May 2016 12:32:23 +0300
Subject: [PATCH v2 5/5] usb: dwc3: rockchip: add devicetree bindings
 documentation
In-Reply-To: <1463133155-20047-1-git-send-email-william.wu@rock-chips.com>
References: <1463133155-20047-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <87a8jfu7h4.fsf@linux.intel.com>


Hi,

William Wu <william.wu at rock-chips.com> writes:
> This patch documents the device tree documentation required for
> Rockchip USB3.0 core wrapper consist of USB3.0 IP from Synopsys.
>
> It could operate in device mode (SS, HS, FS) and host
> mode (SS, HS, FS, LS).
>
> Signed-off-by: William Wu <william.wu at rock-chips.com>
> ---
> Changes in v2:
> - add rockchip,dwc3.txt to Documentation/devicetree/bindings/ (Felipe, Brian)
>
>  .../devicetree/bindings/usb/rockchip,dwc3.txt      | 45 ++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
>
> diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
> new file mode 100644
> index 0000000..10303d9
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
> @@ -0,0 +1,45 @@
> +Rockchip SuperSpeed DWC3 USB SoC controller
> +
> +Required properties:
> +- compatible:	should contain "rockchip,dwc3"
> +- clocks:		A list of phandle + clock-specifier pairs for the
> +				clocks listed in clock-names
> +- clock-names:	Should contain the following:
> +  "clk_usb3otg0_ref"	Controller reference clk
> +  "clk_usb3otg0_suspend"Controller suspend clk, can use 24 MHz or 32 KHz
> +  "aclk_usb3"		Master/Core clock, have to be >= 62.5 MHz for SS operation
> +
> +
> +Optional clocks:
> +  "aclk_usb3otg0"	Aclk for specific usb controller clock.
> +  "aclk_usb3_rksoc_axi_perf"  USB AXI perf clock.  Not present on all platforms.
> +  "aclk_usb3_grf"	USB grf clock.  Not present on all platforms.
> +
> +Required child node:
> +A child node must exist to represent the core DWC3 IP block. The name of
> +the node is not important. The content of the node is defined in dwc3.txt.
> +
> +Phy documentation is provided in the following places:
> +
> +Example device nodes:
> +
> +	usbdrd3_0: usb at fe800000 {
> +

no reg property?
		compatible = "rockchip,dwc3";
> +		clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
> +			 <&cru ACLK_USB3>, <&cru ACLK_USB3OTG0>,
> +			 <&cru ACLK_USB3_RKSOC_AXI_PERF>, <&cru ACLK_USB3_GRF>;
> +		clock-names = "clk_usb3otg0_ref", "clk_usb3otg0_suspend",
> +			      "aclk_usb3", "aclk_usb3otg0",
> +			      "aclk_usb3_rksoc_axi_perf", "aclk_usb3_grf";
> +		#address-cells = <2>;
> +		#size-cells = <2>;
> +		ranges;
> +		status = "disabled";
> +		usbdrd_dwc3_0: dwc3 {

no address here?

> +			compatible = "snps,dwc3";
> +			reg = <0x0 0xfe800000 0x0 0x100000>;
> +			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
> +			dr_mode = "otg";
> +			status = "disabled";
> +		};
> +	};
> -- 
> 1.9.1
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 818 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160524/d865be92/attachment-0001.sig>

From jh80.chung at samsung.com  Tue May 24 02:57:55 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Tue, 24 May 2016 18:57:55 +0900
Subject: [PATCH v5 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <1463976835-29780-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <CGME20160523041529epcas1p3ab7a79120c0ef135fbca109eede66883@epcas1p3.samsung.com>
 <1463976835-29780-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <574425A3.6090303@samsung.com>

On 05/23/2016 01:13 PM, Shawn Lin wrote:
> Controllers use data strobe line to latch data from devices
> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
> introduces enhanced strobe mode for latching cmd response from
> emmc devices to host controllers. This new feature is optional,
> so it depends both on device's cap and host's cap to decide
> whether to use it or not.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
> 
> Changes in v5: None
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/mmc/core/bus.c   |  3 +-
>  drivers/mmc/core/core.c  |  9 ++++++
>  drivers/mmc/core/mmc.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
>  include/linux/mmc/card.h |  1 +
>  include/linux/mmc/host.h | 11 +++++++
>  include/linux/mmc/mmc.h  |  3 ++
>  6 files changed, 108 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index 4bc48f1..c64266f 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			type);
>  	} else {
> -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>  			mmc_hostname(card->host),
>  			mmc_card_uhs(card) ? "ultra high speed " :
>  			(mmc_card_hs(card) ? "high speed " : ""),
>  			mmc_card_hs400(card) ? "HS400 " :
>  			(mmc_card_hs200(card) ? "HS200 " : ""),
> +			mmc_card_hs400es(card) ? "Enhanced strobe " : "",
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			uhs_bus_speed_mode, type, card->rca);
>  	}
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 99275e4..b0c1f07 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -1127,6 +1127,15 @@ void mmc_set_initial_state(struct mmc_host *host)
>  	host->ios.bus_width = MMC_BUS_WIDTH_1;
>  	host->ios.timing = MMC_TIMING_LEGACY;
>  	host->ios.drv_type = 0;
> +	host->ios.enhanced_strobe = false;
> +
> +	/*
> +	 * Make sure we are in non-enhanced strobe mode before we
> +	 * actually enable it in ext_csd.
> +	 */
> +	if ((host->caps2 & MMC_CAP2_HS400_ES) &&
> +	     host->ops->hs400_enhanced_strobe)
> +		host->ops->hs400_enhanced_strobe(host, &host->ios);


I wonder what is enhanced_strobe's purpose.
When i saw your patches, this is used to check whether timing is strobe or not in sdhci-of-arasan, right?
If ios.enhanced_strobe is used only this purpose, is it possible to use the below?

host->ops->hs400_enhanced_strobe(host, false/true); ?

This callback is also called only two locations..init (false) and switch hs400es (true).

>  
>  	mmc_set_ios(host);
>  }
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index f99c47e..9dc91ba 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>  		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>  	}
>  
> +	if ((caps2 & MMC_CAP2_HS400_ES) &&
> +	    card->ext_csd.strobe_support &&
> +	    (avail_type & EXT_CSD_CARD_TYPE_HS400))
> +		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
> +
>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>  	card->mmc_avail_type = avail_type;
> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>  			mmc_card_set_blockaddr(card);
>  	}
>  
> +	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>  	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>  	mmc_select_card_type(card);
>  
> @@ -1216,6 +1222,78 @@ out_err:
>  	return err;
>  }
>  
> +static int mmc_select_hs400es(struct mmc_card *card)
> +{
> +	struct mmc_host *host = card->host;
> +	int err = 0;
> +	u8 val;
> +
> +	if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
> +		err = -ENOTSUPP;
> +		goto out_err;
> +	}
> +
> +	err = mmc_select_bus_width(card);
> +	if (IS_ERR_VALUE(err))
> +		goto out_err;
> +
> +	/* Switch card to HS mode */
> +	err = mmc_select_hs(card);
> +	if (err) {
> +		pr_err("%s: switch to high-speed failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
> +
> +	/* Switch card to DDR with strobe bit */
> +	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			 EXT_CSD_BUS_WIDTH,
> +			 val,
> +			 card->ext_csd.generic_cmd6_time);
> +	if (err) {
> +		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	/* Switch card to HS400 */
> +	val = EXT_CSD_TIMING_HS400 |
> +	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
> +	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			   EXT_CSD_HS_TIMING, val,
> +			   card->ext_csd.generic_cmd6_time,
> +			   true, false, true);
> +	if (err) {
> +		pr_err("%s: switch to hs400es failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	/* Set host controller to HS400 timing and frequency */
> +	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> +
> +	/* Controller enable enhanced strobe function */
> +	host->ios.enhanced_strobe = true;
> +	if (host->ops->hs400_enhanced_strobe)
> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
> +
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
> +
> +	return 0;
> +
> +out_err:

If ios.ehanced_strobe is really needs, you need to set from true to false at here?

Best Regards,
Jaehoon Chung

> +	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
> +	       __func__, err);
> +	return err;
> +}
> +
>  static void mmc_select_driver_type(struct mmc_card *card)
>  {
>  	int card_drv_type, drive_strength, drv_type;
> @@ -1297,7 +1375,7 @@ err:
>  }
>  
>  /*
> - * Activate High Speed or HS200 mode if supported.
> + * Activate High Speed, HS200 or HS400ES mode if supported.
>   */
>  static int mmc_select_timing(struct mmc_card *card)
>  {
> @@ -1306,7 +1384,9 @@ static int mmc_select_timing(struct mmc_card *card)
>  	if (!mmc_can_ext_csd(card))
>  		goto bus_speed;
>  
> -	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
> +		err = mmc_select_hs400es(card);
> +	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>  		err = mmc_select_hs200(card);
>  	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>  		err = mmc_select_hs(card);
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index eb0151b..22defc2 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>  	u8			raw_partition_support;	/* 160 */
>  	u8			raw_rpmb_size_mult;	/* 168 */
>  	u8			raw_erased_mem_count;	/* 181 */
> +	u8			strobe_support;		/* 184 */
>  	u8			raw_ext_csd_structure;	/* 194 */
>  	u8			raw_card_type;		/* 196 */
>  	u8			raw_driver_strength;	/* 197 */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 2a06fb0..0eabb72 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -19,6 +19,7 @@
>  
>  #include <linux/mmc/core.h>
>  #include <linux/mmc/card.h>
> +#include <linux/mmc/mmc.h>
>  #include <linux/mmc/pm.h>
>  
>  struct mmc_ios {
> @@ -77,6 +78,8 @@ struct mmc_ios {
>  #define MMC_SET_DRIVER_TYPE_A	1
>  #define MMC_SET_DRIVER_TYPE_C	2
>  #define MMC_SET_DRIVER_TYPE_D	3
> +
> +	bool enhanced_strobe;			/* hs400es selection */
>  };
>  
>  struct mmc_host_ops {
> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>  
>  	/* Prepare HS400 target operating frequency depending host driver */
>  	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
> +	/* Prepare enhanced strobe depending host driver */
> +	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
> +					 struct mmc_ios *ios);
>  	int	(*select_drive_strength)(struct mmc_card *card,
>  					 unsigned int max_dtr, int host_drv,
>  					 int card_drv, int *drv_type);
> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>  	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>  }
>  
> +static inline bool mmc_card_hs400es(struct mmc_card *card)
> +{
> +	return card->host->ios.enhanced_strobe;
> +}
> +
>  void mmc_retune_timer_stop(struct mmc_host *host);
>  
>  static inline void mmc_retune_needed(struct mmc_host *host)
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 15f2c4a..c376209 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -297,6 +297,7 @@ struct _mmc_csd {
>  #define EXT_CSD_PART_CONFIG		179	/* R/W */
>  #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
>  #define EXT_CSD_BUS_WIDTH		183	/* R/W */
> +#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
>  #define EXT_CSD_HS_TIMING		185	/* R/W */
>  #define EXT_CSD_POWER_CLASS		187	/* R/W */
>  #define EXT_CSD_REV			192	/* RO */
> @@ -380,12 +381,14 @@ struct _mmc_csd {
>  #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
>  #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
>  					 EXT_CSD_CARD_TYPE_HS400_1_2V)
> +#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
>  
>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
>  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
>  
>  #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
>  #define EXT_CSD_TIMING_HS	1	/* High speed */
> 



From catalin.marinas at arm.com  Tue May 24 02:59:27 2016
From: catalin.marinas at arm.com (Catalin Marinas)
Date: Tue, 24 May 2016 10:59:27 +0100
Subject: [PATCH 4/5] iommu/rockchip: add ARM64 cache flush operation for
 iommu
In-Reply-To: <5743BCF5.8030607@rock-chips.com>
References: <1463967439-13354-1-git-send-email-zhengsq@rock-chips.com>
 <1463967439-13354-5-git-send-email-zhengsq@rock-chips.com>
 <5742DEFE.1040902@arm.com>
 <20160523133500.GF4892@e104818-lin.cambridge.arm.com>
 <5743BCF5.8030607@rock-chips.com>
Message-ID: <20160524095927.GS4892@e104818-lin.cambridge.arm.com>

On Tue, May 24, 2016 at 10:31:17AM +0800, Shunqian Zheng wrote:
> On 2016?05?23? 21:35, Catalin Marinas wrote:
> >On Mon, May 23, 2016 at 11:44:14AM +0100, Robin Murphy wrote:
> >>On 23/05/16 02:37, Shunqian Zheng wrote:
> >>>From: Simon <xxm at rock-chips.com>
> >>>
> >>>Signed-off-by: Simon <xxm at rock-chips.com>
> >>>---
> >>>  drivers/iommu/rockchip-iommu.c | 4 ++++
> >>>  1 file changed, 4 insertions(+)
> >>>
> >>>diff --git a/drivers/iommu/rockchip-iommu.c b/drivers/iommu/rockchip-iommu.c
> >>>index 043d18c..1741b65 100644
> >>>--- a/drivers/iommu/rockchip-iommu.c
> >>>+++ b/drivers/iommu/rockchip-iommu.c
> >>>@@ -95,12 +95,16 @@ struct rk_iommu {
> >>>
> >>>  static inline void rk_table_flush(u32 *va, unsigned int count)
> >>>  {
> >>>+#if defined(CONFIG_ARM)
> >>>  	phys_addr_t pa_start = virt_to_phys(va);
> >>>  	phys_addr_t pa_end = virt_to_phys(va + count);
> >>>  	size_t size = pa_end - pa_start;
> >>>
> >>>  	__cpuc_flush_dcache_area(va, size);
> >>>  	outer_flush_range(pa_start, pa_end);
> >>>+#elif defined(CONFIG_ARM64)
> >>>+	__dma_flush_range(va, va + count);
> >>>+#endif
> >>Ugh, please don't use arch-private cache maintenance functions directly from
> >>a driver. Allocating/mapping page tables to be read by the IOMMU is still
> >>DMA, so using the DMA APIs is the correct way to manage them, *especially*
> >>if it needs to work across multiple architectures.
> 
> It's easier for us if changing  the __dma_flush_range() to
> __flush_dcache_area() is acceptable here?

It's not really acceptable for arm64, nor for arm32. Please fix this
driver in a similar way to commit e3c971960fd4 ("iommu/tegra-smmu:
Convert to use DMA API").

The only place where we allowed __flush_dcache_area() is in the GICv3
driver and that's because it hasn't been wired as a platform device
(yet).

-- 
Catalin


From tomeu.vizoso at collabora.com  Tue May 24 03:11:27 2016
From: tomeu.vizoso at collabora.com (Tomeu Vizoso)
Date: Tue, 24 May 2016 12:11:27 +0200
Subject: [PATCH 1/2] drm/rockchip: vop: Do check if an update is pending
 during disable
In-Reply-To: <5742A41B.8030308@rock-chips.com>
References: <1459937686-9142-1-git-send-email-tomeu.vizoso@collabora.com>
 <5707043D.6060706@rock-chips.com>
 <CAAObsKAeAjUP1retiZqo5geOK2OkVjKvSB6g6nvGTh_rdNiFJQ@mail.gmail.com>
 <570AFAC2.8080907@rock-chips.com>
 <CAAObsKCmPZBaSudVJy8BPThhoZw8VVqxicqsmc8diApajD57nA@mail.gmail.com>
 <CAAObsKBXxb8ZS3CqLy4qsDRWLvT=w2ACANCcDLE5B47nRKtvBw@mail.gmail.com>
 <5742A41B.8030308@rock-chips.com>
Message-ID: <CAAObsKAj9Ja56buTixvp0EVBk=xE4JCXPPwXdviweHkmUQb2xg@mail.gmail.com>

On 23 May 2016 at 08:32, Mark yao <mark.yao at rock-chips.com> wrote:
> On 2016?05?05? 17:34, Tomeu Vizoso wrote:
>>
>> On 20 April 2016 at 16:23, Tomeu Vizoso <tomeu.vizoso at collabora.com>
>> wrote:
>>>
>>> On 11 April 2016 at 03:15, Mark yao <mark.yao at rock-chips.com> wrote:
>>>>
>>>> On 2016?04?08? 18:54, Tomeu Vizoso wrote:
>>>>>
>>>>> On 8 April 2016 at 03:07, Mark yao <mark.yao at rock-chips.com> wrote:
>>>>>>
>>>>>> On 2016?04?06? 18:14, Tomeu Vizoso wrote:
>>>>>>
>>>>>> When a plane is being disabled but it's still enabled, do check if the
>>>>>> previous update has been completed by reading yrgb_mst back.
>>>>>>
>>>>>> Otherwise, pending pageflips would remain pending after a CRTC is
>>>>>> disabled.
>>>>>>
>>>>>> Signed-off-by: Tomeu Vizoso <tomeu.vizoso at collabora.com>
>>>>>> ---
>>>>>>    drivers/gpu/drm/rockchip/rockchip_drm_vop.c | 5 +++--
>>>>>>    1 file changed, 3 insertions(+), 2 deletions(-)
>>>>>>
>>>>>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>>>> b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>>>> index a9b1e8b5ac85..f46b1fd1887b 100644
>>>>>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>>>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>>>>>> @@ -1064,8 +1064,9 @@ static bool vop_win_pending_is_complete(struct
>>>>>> vop_win
>>>>>> *vop_win)
>>>>>>     struct vop_plane_state *state = to_vop_plane_state(plane->state);
>>>>>>     dma_addr_t yrgb_mst;
>>>>>>
>>>>>> - if (!state->enable)
>>>>>> - return VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0;
>>>>>> + if (!state->enable &&
>>>>>> +    VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0)
>>>>>> + return true;
>>>>>>
>>>>>>
>>>>>> It is wrong, the patch would cause a bug.
>>>>>>
>>>>>> when state->enable is 0, check yrgb_mst == state->yrgb_mst always be
>>>>>> true,
>>>>>> because state->yrgb_mst not update on plane disabled funtion, that
>>>>>> would
>>>>>> cause iommu crash.
>>>>>
>>>>> Sorry, but I don't understand where's the bug and what could cause
>>>>> that crash. What the existing code was doing is saying that a pageflip
>>>>> event is still pending if we have told the plane to disable but for
>>>>> some reason it hasn't yet.
>>>>>
>>>>> With this modification, if we read back that it's already disabled, we
>>>>> return true as before. But if we read back that it isn't disabled yet,
>>>>> then we still check the fb pointers and compare them.
>>>>>
>>>>> The iommu mapping is removed when the _CRTC_ is disabled, and what
>>>>> this series does is to wait for the pending pageflip to finish before
>>>>> conitnuing with CRTC disablement.
>>>>
>>>>
>>>> the iommu mapping will unmap after plane disabled, we need sure that the
>>>> plane really disabled before unmap, if not, the unmap may call before
>>>> plane
>>>> really disable, vop may access unmap address, then would get iommu page
>>>> fault.
>>>
>>> Sorry, but I still don't see the error condition that you are
>>> describing. AFAICS, the unmap will happen after the last pageflip has
>>> completed.
>>>
>>>>>> About pending pageflips would remain pending, can you  describe more
>>>>>> info
>>>>>> about it? I think those pending pageflips should be ignore when CRTC
>>>>>> is
>>>>>> disabled.
>>>>>
>>>>> Well, right now in rockchip-drm pending pageflips won't be ignored
>>>>> when a CRTC is disabled, but will be delivered when it's re-enabled.
>>>>>
>>>>> If they would be to be ignored (understanding that as dropped), that
>>>>> would require modifications to clients so they keep track of which fbs
>>>>> were used in a particular crtc and destroy them when the crtc is
>>>>> disabled, but that would be incorrect when using the i915 DRM driver
>>>>> (I also assume others do the same). Given that the pageflip ioctl
>>>>> isn't driver-specific, I think there cannot be such a difference in
>>>>> behavior between drivers.
>>>>>
>>>>> With the current behavior (pending pageflip events being delayed until
>>>>> the CRTC is enabled again), compositors and other clients will be
>>>>> holding on to the fb in the pending pageflip until an arbitrary point
>>>>> in the future that may not ever come. To me that sounds like a serious
>>>>> modification of the assumptions on fb lifecycle that might not be
>>>>> warranted.
>>>>>
>>>>> So in summary, even if I haven't found any explicit documentation on
>>>>> this, I think the ABI is that any pending pageflips are to be
>>>>> delivered when that CRTC is being disabled and not later.
>>>>
>>>>
>>>> on drivers/gpu/drm/rockchip/rockchip_drm_fb.c
>>>>
>>>> drm_atomic_helper_commit_planes(dev, state, true);
>>>> rockchip_atomic_wait_for_complete(dev, state);
>>>>
>>>> We set active_only = true, I think planes can only update when crtc is
>>>> active. and rockchip_atomic_wait_for_complete only wait when crtc is
>>>> active.
>>>
>>> That's fine, but if a pageflip is pending when the client requests the
>>> CRTC to be disabled, we need to wait for the event to be emitted
>>> before we actually disable the HW.
>>
>> Hi Mark,
>>
>> could you tell me if you agree that there's a bug that needs to be
>> solved, and if so, what do you think we should do about it?
>
> Hi Tomeu
>
> Sorry for reply late.
> I don't agree the changes:
>
> - if (!state->enable)
> - return VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0;
> + if (!state->enable &&
> +    VOP_WIN_GET(vop_win->vop, vop_win->data, enable) == 0)
> + return true;
>
> This changes actually would lead a bug.
> when we disable a plane, the vop_win_pending_is_complete would always return
> true, That is not allowed, would cause fb free too early.

Ok, maybe I need to ask you first what the original block of code
intended to achieve. The TRM I have is very terse and I don't find any
explanation there. The battery of tests I have pass just fine without
it.

> Does this patch is needed for "[PATCH 2/2] drm/rockchip: vop: Wait for
> pending events when disabling a CRTC"

Yes, this function is currently returning false when the pageflip has
been completed but the plan has been already disabled.

If you have any different idea of how to fix this bug, please share.

Thanks,

Tomeu


From shawn.lin at rock-chips.com  Tue May 24 03:11:50 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 24 May 2016 18:11:50 +0800
Subject: [PATCH v5 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <574425A3.6090303@samsung.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <CGME20160523041529epcas1p3ab7a79120c0ef135fbca109eede66883@epcas1p3.samsung.com>
 <1463976835-29780-1-git-send-email-shawn.lin@rock-chips.com>
 <574425A3.6090303@samsung.com>
Message-ID: <1f67fa2e-9a14-819d-8d75-3b35be819f0d@rock-chips.com>

? 2016/5/24 17:57, Jaehoon Chung ??:
> On 05/23/2016 01:13 PM, Shawn Lin wrote:
>> Controllers use data strobe line to latch data from devices
>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>> introduces enhanced strobe mode for latching cmd response from
>> emmc devices to host controllers. This new feature is optional,
>> so it depends both on device's cap and host's cap to decide
>> whether to use it or not.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> ---
>>
>> Changes in v5: None
>> Changes in v4: None
>> Changes in v3: None
>> Changes in v2: None
>>
>>  drivers/mmc/core/bus.c   |  3 +-
>>  drivers/mmc/core/core.c  |  9 ++++++
>>  drivers/mmc/core/mmc.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
>>  include/linux/mmc/card.h |  1 +
>>  include/linux/mmc/host.h | 11 +++++++
>>  include/linux/mmc/mmc.h  |  3 ++
>>  6 files changed, 108 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> index 4bc48f1..c64266f 100644
>> --- a/drivers/mmc/core/bus.c
>> +++ b/drivers/mmc/core/bus.c
>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>  			mmc_card_ddr52(card) ? "DDR " : "",
>>  			type);
>>  	} else {
>> -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>> +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>  			mmc_hostname(card->host),
>>  			mmc_card_uhs(card) ? "ultra high speed " :
>>  			(mmc_card_hs(card) ? "high speed " : ""),
>>  			mmc_card_hs400(card) ? "HS400 " :
>>  			(mmc_card_hs200(card) ? "HS200 " : ""),
>> +			mmc_card_hs400es(card) ? "Enhanced strobe " : "",
>>  			mmc_card_ddr52(card) ? "DDR " : "",
>>  			uhs_bus_speed_mode, type, card->rca);
>>  	}
>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> index 99275e4..b0c1f07 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -1127,6 +1127,15 @@ void mmc_set_initial_state(struct mmc_host *host)
>>  	host->ios.bus_width = MMC_BUS_WIDTH_1;
>>  	host->ios.timing = MMC_TIMING_LEGACY;
>>  	host->ios.drv_type = 0;
>> +	host->ios.enhanced_strobe = false;
>> +
>> +	/*
>> +	 * Make sure we are in non-enhanced strobe mode before we
>> +	 * actually enable it in ext_csd.
>> +	 */
>> +	if ((host->caps2 & MMC_CAP2_HS400_ES) &&
>> +	     host->ops->hs400_enhanced_strobe)
>> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
>
>
> I wonder what is enhanced_strobe's purpose.
> When i saw your patches, this is used to check whether timing is strobe or not in sdhci-of-arasan, right?


Also we use it for debugfs.

> If ios.enhanced_strobe is used only this purpose, is it possible to use the below?
>
> host->ops->hs400_enhanced_strobe(host, false/true); ?
>
> This callback is also called only two locations..init (false) and switch hs400es (true).

It was suggested by Adrian. I'm ok with both of them.

>
>>
>>  	mmc_set_ios(host);
>>  }
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index f99c47e..9dc91ba 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>>  		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>>  	}
>>
>> +	if ((caps2 & MMC_CAP2_HS400_ES) &&
>> +	    card->ext_csd.strobe_support &&
>> +	    (avail_type & EXT_CSD_CARD_TYPE_HS400))
>> +		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
>> +
>>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>>  	card->mmc_avail_type = avail_type;
>> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>  			mmc_card_set_blockaddr(card);
>>  	}
>>
>> +	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>>  	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>  	mmc_select_card_type(card);
>>
>> @@ -1216,6 +1222,78 @@ out_err:
>>  	return err;
>>  }
>>
>> +static int mmc_select_hs400es(struct mmc_card *card)
>> +{
>> +	struct mmc_host *host = card->host;
>> +	int err = 0;
>> +	u8 val;
>> +
>> +	if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
>> +		err = -ENOTSUPP;
>> +		goto out_err;
>> +	}
>> +
>> +	err = mmc_select_bus_width(card);
>> +	if (IS_ERR_VALUE(err))
>> +		goto out_err;
>> +
>> +	/* Switch card to HS mode */
>> +	err = mmc_select_hs(card);
>> +	if (err) {
>> +		pr_err("%s: switch to high-speed failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	err = mmc_switch_status(card);
>> +	if (err)
>> +		goto out_err;
>> +
>> +	/* Switch card to DDR with strobe bit */
>> +	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
>> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +			 EXT_CSD_BUS_WIDTH,
>> +			 val,
>> +			 card->ext_csd.generic_cmd6_time);
>> +	if (err) {
>> +		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	/* Switch card to HS400 */
>> +	val = EXT_CSD_TIMING_HS400 |
>> +	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
>> +	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +			   EXT_CSD_HS_TIMING, val,
>> +			   card->ext_csd.generic_cmd6_time,
>> +			   true, false, true);
>> +	if (err) {
>> +		pr_err("%s: switch to hs400es failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	/* Set host controller to HS400 timing and frequency */
>> +	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>> +
>> +	/* Controller enable enhanced strobe function */
>> +	host->ios.enhanced_strobe = true;
>> +	if (host->ops->hs400_enhanced_strobe)
>> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
>> +
>> +	err = mmc_switch_status(card);
>> +	if (err)
>> +		goto out_err;
>> +
>> +	return 0;
>> +
>> +out_err:
>
> If ios.ehanced_strobe is really needs, you need to set from true to false at here?

I don't think so. If failing to run into HS400es, I'd not expect it
fallback to HS400, and why not let mmc core retring it. We currently
don't have speed-mode fallback mechanism,  right?

>
> Best Regards,
> Jaehoon Chung
>
>> +	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
>> +	       __func__, err);
>> +	return err;
>> +}
>> +
>>  static void mmc_select_driver_type(struct mmc_card *card)
>>  {
>>  	int card_drv_type, drive_strength, drv_type;
>> @@ -1297,7 +1375,7 @@ err:
>>  }
>>
>>  /*
>> - * Activate High Speed or HS200 mode if supported.
>> + * Activate High Speed, HS200 or HS400ES mode if supported.
>>   */
>>  static int mmc_select_timing(struct mmc_card *card)
>>  {
>> @@ -1306,7 +1384,9 @@ static int mmc_select_timing(struct mmc_card *card)
>>  	if (!mmc_can_ext_csd(card))
>>  		goto bus_speed;
>>
>> -	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
>> +		err = mmc_select_hs400es(card);
>> +	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>  		err = mmc_select_hs200(card);
>>  	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>  		err = mmc_select_hs(card);
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index eb0151b..22defc2 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>>  	u8			raw_partition_support;	/* 160 */
>>  	u8			raw_rpmb_size_mult;	/* 168 */
>>  	u8			raw_erased_mem_count;	/* 181 */
>> +	u8			strobe_support;		/* 184 */
>>  	u8			raw_ext_csd_structure;	/* 194 */
>>  	u8			raw_card_type;		/* 196 */
>>  	u8			raw_driver_strength;	/* 197 */
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index 2a06fb0..0eabb72 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -19,6 +19,7 @@
>>
>>  #include <linux/mmc/core.h>
>>  #include <linux/mmc/card.h>
>> +#include <linux/mmc/mmc.h>
>>  #include <linux/mmc/pm.h>
>>
>>  struct mmc_ios {
>> @@ -77,6 +78,8 @@ struct mmc_ios {
>>  #define MMC_SET_DRIVER_TYPE_A	1
>>  #define MMC_SET_DRIVER_TYPE_C	2
>>  #define MMC_SET_DRIVER_TYPE_D	3
>> +
>> +	bool enhanced_strobe;			/* hs400es selection */
>>  };
>>
>>  struct mmc_host_ops {
>> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>>
>>  	/* Prepare HS400 target operating frequency depending host driver */
>>  	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>> +	/* Prepare enhanced strobe depending host driver */
>> +	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
>> +					 struct mmc_ios *ios);
>>  	int	(*select_drive_strength)(struct mmc_card *card,
>>  					 unsigned int max_dtr, int host_drv,
>>  					 int card_drv, int *drv_type);
>> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>>  	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>>  }
>>
>> +static inline bool mmc_card_hs400es(struct mmc_card *card)
>> +{
>> +	return card->host->ios.enhanced_strobe;
>> +}
>> +
>>  void mmc_retune_timer_stop(struct mmc_host *host);
>>
>>  static inline void mmc_retune_needed(struct mmc_host *host)
>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> index 15f2c4a..c376209 100644
>> --- a/include/linux/mmc/mmc.h
>> +++ b/include/linux/mmc/mmc.h
>> @@ -297,6 +297,7 @@ struct _mmc_csd {
>>  #define EXT_CSD_PART_CONFIG		179	/* R/W */
>>  #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
>>  #define EXT_CSD_BUS_WIDTH		183	/* R/W */
>> +#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
>>  #define EXT_CSD_HS_TIMING		185	/* R/W */
>>  #define EXT_CSD_POWER_CLASS		187	/* R/W */
>>  #define EXT_CSD_REV			192	/* RO */
>> @@ -380,12 +381,14 @@ struct _mmc_csd {
>>  #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
>>  #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
>>  					 EXT_CSD_CARD_TYPE_HS400_1_2V)
>> +#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
>>
>>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
>>  #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
>>  #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
>>
>>  #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
>>  #define EXT_CSD_TIMING_HS	1	/* High speed */
>>
>
>
>
>


-- 
Best Regards
Shawn Lin



From jh80.chung at samsung.com  Tue May 24 03:15:59 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Tue, 24 May 2016 19:15:59 +0900
Subject: [PATCH v5 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <1f67fa2e-9a14-819d-8d75-3b35be819f0d@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <CGME20160523041529epcas1p3ab7a79120c0ef135fbca109eede66883@epcas1p3.samsung.com>
 <1463976835-29780-1-git-send-email-shawn.lin@rock-chips.com>
 <574425A3.6090303@samsung.com>
 <1f67fa2e-9a14-819d-8d75-3b35be819f0d@rock-chips.com>
Message-ID: <574429DF.1000501@samsung.com>

On 05/24/2016 07:11 PM, Shawn Lin wrote:
> ? 2016/5/24 17:57, Jaehoon Chung ??:
>> On 05/23/2016 01:13 PM, Shawn Lin wrote:
>>> Controllers use data strobe line to latch data from devices
>>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>>> introduces enhanced strobe mode for latching cmd response from
>>> emmc devices to host controllers. This new feature is optional,
>>> so it depends both on device's cap and host's cap to decide
>>> whether to use it or not.
>>>
>>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>> ---
>>>
>>> Changes in v5: None
>>> Changes in v4: None
>>> Changes in v3: None
>>> Changes in v2: None
>>>
>>>  drivers/mmc/core/bus.c   |  3 +-
>>>  drivers/mmc/core/core.c  |  9 ++++++
>>>  drivers/mmc/core/mmc.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
>>>  include/linux/mmc/card.h |  1 +
>>>  include/linux/mmc/host.h | 11 +++++++
>>>  include/linux/mmc/mmc.h  |  3 ++
>>>  6 files changed, 108 insertions(+), 3 deletions(-)
>>>
>>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>>> index 4bc48f1..c64266f 100644
>>> --- a/drivers/mmc/core/bus.c
>>> +++ b/drivers/mmc/core/bus.c
>>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>>              mmc_card_ddr52(card) ? "DDR " : "",
>>>              type);
>>>      } else {
>>> -        pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>>> +        pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>>              mmc_hostname(card->host),
>>>              mmc_card_uhs(card) ? "ultra high speed " :
>>>              (mmc_card_hs(card) ? "high speed " : ""),
>>>              mmc_card_hs400(card) ? "HS400 " :
>>>              (mmc_card_hs200(card) ? "HS200 " : ""),
>>> +            mmc_card_hs400es(card) ? "Enhanced strobe " : "",
>>>              mmc_card_ddr52(card) ? "DDR " : "",
>>>              uhs_bus_speed_mode, type, card->rca);
>>>      }
>>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>>> index 99275e4..b0c1f07 100644
>>> --- a/drivers/mmc/core/core.c
>>> +++ b/drivers/mmc/core/core.c
>>> @@ -1127,6 +1127,15 @@ void mmc_set_initial_state(struct mmc_host *host)
>>>      host->ios.bus_width = MMC_BUS_WIDTH_1;
>>>      host->ios.timing = MMC_TIMING_LEGACY;
>>>      host->ios.drv_type = 0;
>>> +    host->ios.enhanced_strobe = false;
>>> +
>>> +    /*
>>> +     * Make sure we are in non-enhanced strobe mode before we
>>> +     * actually enable it in ext_csd.
>>> +     */
>>> +    if ((host->caps2 & MMC_CAP2_HS400_ES) &&
>>> +         host->ops->hs400_enhanced_strobe)
>>> +        host->ops->hs400_enhanced_strobe(host, &host->ios);
>>
>>
>> I wonder what is enhanced_strobe's purpose.
>> When i saw your patches, this is used to check whether timing is strobe or not in sdhci-of-arasan, right?
> 
> 
> Also we use it for debugfs.
> 
>> If ios.enhanced_strobe is used only this purpose, is it possible to use the below?
>>
>> host->ops->hs400_enhanced_strobe(host, false/true); ?
>>
>> This callback is also called only two locations..init (false) and switch hs400es (true).
> 
> It was suggested by Adrian. I'm ok with both of them.

I don't mind what using.. :) It's your preference.

> 
>>
>>>
>>>      mmc_set_ios(host);
>>>  }
>>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>>> index f99c47e..9dc91ba 100644
>>> --- a/drivers/mmc/core/mmc.c
>>> +++ b/drivers/mmc/core/mmc.c
>>> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>>>          avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>>>      }
>>>
>>> +    if ((caps2 & MMC_CAP2_HS400_ES) &&
>>> +        card->ext_csd.strobe_support &&
>>> +        (avail_type & EXT_CSD_CARD_TYPE_HS400))
>>> +        avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
>>> +
>>>      card->ext_csd.hs_max_dtr = hs_max_dtr;
>>>      card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>>>      card->mmc_avail_type = avail_type;
>>> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>>              mmc_card_set_blockaddr(card);
>>>      }
>>>
>>> +    card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>>>      card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>>      mmc_select_card_type(card);
>>>
>>> @@ -1216,6 +1222,78 @@ out_err:
>>>      return err;
>>>  }
>>>
>>> +static int mmc_select_hs400es(struct mmc_card *card)
>>> +{
>>> +    struct mmc_host *host = card->host;
>>> +    int err = 0;
>>> +    u8 val;
>>> +
>>> +    if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
>>> +        err = -ENOTSUPP;
>>> +        goto out_err;
>>> +    }
>>> +
>>> +    err = mmc_select_bus_width(card);
>>> +    if (IS_ERR_VALUE(err))
>>> +        goto out_err;
>>> +
>>> +    /* Switch card to HS mode */
>>> +    err = mmc_select_hs(card);
>>> +    if (err) {
>>> +        pr_err("%s: switch to high-speed failed, err:%d\n",
>>> +            mmc_hostname(host), err);
>>> +        goto out_err;
>>> +    }
>>> +
>>> +    err = mmc_switch_status(card);
>>> +    if (err)
>>> +        goto out_err;
>>> +
>>> +    /* Switch card to DDR with strobe bit */
>>> +    val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
>>> +    err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>> +             EXT_CSD_BUS_WIDTH,
>>> +             val,
>>> +             card->ext_csd.generic_cmd6_time);
>>> +    if (err) {
>>> +        pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
>>> +            mmc_hostname(host), err);
>>> +        goto out_err;
>>> +    }
>>> +
>>> +    /* Switch card to HS400 */
>>> +    val = EXT_CSD_TIMING_HS400 |
>>> +          card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
>>> +    err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>>> +               EXT_CSD_HS_TIMING, val,
>>> +               card->ext_csd.generic_cmd6_time,
>>> +               true, false, true);
>>> +    if (err) {
>>> +        pr_err("%s: switch to hs400es failed, err:%d\n",
>>> +            mmc_hostname(host), err);
>>> +        goto out_err;
>>> +    }
>>> +
>>> +    /* Set host controller to HS400 timing and frequency */
>>> +    mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>>> +
>>> +    /* Controller enable enhanced strobe function */
>>> +    host->ios.enhanced_strobe = true;
>>> +    if (host->ops->hs400_enhanced_strobe)
>>> +        host->ops->hs400_enhanced_strobe(host, &host->ios);
>>> +
>>> +    err = mmc_switch_status(card);
>>> +    if (err)
>>> +        goto out_err;
>>> +
>>> +    return 0;
>>> +
>>> +out_err:
>>
>> If ios.ehanced_strobe is really needs, you need to set from true to false at here?
> 
> I don't think so. If failing to run into HS400es, I'd not expect it
> fallback to HS400, and why not let mmc core retring it. We currently
> don't have speed-mode fallback mechanism,  right?

Ok. I have tested with my exynos board. It's working fine.

Tested-by: Jaehoon Chung <jh80.chung at samsung.com>
Reviewed-by: Jaehoon Chung <jh80.chung at samsung.com>

Best Regards,
Jaehoon Chung

> 
>>
>> Best Regards,
>> Jaehoon Chung
>>
>>> +    pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
>>> +           __func__, err);
>>> +    return err;
>>> +}
>>> +
>>>  static void mmc_select_driver_type(struct mmc_card *card)
>>>  {
>>>      int card_drv_type, drive_strength, drv_type;
>>> @@ -1297,7 +1375,7 @@ err:
>>>  }
>>>
>>>  /*
>>> - * Activate High Speed or HS200 mode if supported.
>>> + * Activate High Speed, HS200 or HS400ES mode if supported.
>>>   */
>>>  static int mmc_select_timing(struct mmc_card *card)
>>>  {
>>> @@ -1306,7 +1384,9 @@ static int mmc_select_timing(struct mmc_card *card)
>>>      if (!mmc_can_ext_csd(card))
>>>          goto bus_speed;
>>>
>>> -    if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>> +    if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
>>> +        err = mmc_select_hs400es(card);
>>> +    else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>>          err = mmc_select_hs200(card);
>>>      else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>>          err = mmc_select_hs(card);
>>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>>> index eb0151b..22defc2 100644
>>> --- a/include/linux/mmc/card.h
>>> +++ b/include/linux/mmc/card.h
>>> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>>>      u8            raw_partition_support;    /* 160 */
>>>      u8            raw_rpmb_size_mult;    /* 168 */
>>>      u8            raw_erased_mem_count;    /* 181 */
>>> +    u8            strobe_support;        /* 184 */
>>>      u8            raw_ext_csd_structure;    /* 194 */
>>>      u8            raw_card_type;        /* 196 */
>>>      u8            raw_driver_strength;    /* 197 */
>>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>>> index 2a06fb0..0eabb72 100644
>>> --- a/include/linux/mmc/host.h
>>> +++ b/include/linux/mmc/host.h
>>> @@ -19,6 +19,7 @@
>>>
>>>  #include <linux/mmc/core.h>
>>>  #include <linux/mmc/card.h>
>>> +#include <linux/mmc/mmc.h>
>>>  #include <linux/mmc/pm.h>
>>>
>>>  struct mmc_ios {
>>> @@ -77,6 +78,8 @@ struct mmc_ios {
>>>  #define MMC_SET_DRIVER_TYPE_A    1
>>>  #define MMC_SET_DRIVER_TYPE_C    2
>>>  #define MMC_SET_DRIVER_TYPE_D    3
>>> +
>>> +    bool enhanced_strobe;            /* hs400es selection */
>>>  };
>>>
>>>  struct mmc_host_ops {
>>> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>>>
>>>      /* Prepare HS400 target operating frequency depending host driver */
>>>      int    (*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>>> +    /* Prepare enhanced strobe depending host driver */
>>> +    void    (*hs400_enhanced_strobe)(struct mmc_host *host,
>>> +                     struct mmc_ios *ios);
>>>      int    (*select_drive_strength)(struct mmc_card *card,
>>>                       unsigned int max_dtr, int host_drv,
>>>                       int card_drv, int *drv_type);
>>> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>>>      return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>>>  }
>>>
>>> +static inline bool mmc_card_hs400es(struct mmc_card *card)
>>> +{
>>> +    return card->host->ios.enhanced_strobe;
>>> +}
>>> +
>>>  void mmc_retune_timer_stop(struct mmc_host *host);
>>>
>>>  static inline void mmc_retune_needed(struct mmc_host *host)
>>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>>> index 15f2c4a..c376209 100644
>>> --- a/include/linux/mmc/mmc.h
>>> +++ b/include/linux/mmc/mmc.h
>>> @@ -297,6 +297,7 @@ struct _mmc_csd {
>>>  #define EXT_CSD_PART_CONFIG        179    /* R/W */
>>>  #define EXT_CSD_ERASED_MEM_CONT        181    /* RO */
>>>  #define EXT_CSD_BUS_WIDTH        183    /* R/W */
>>> +#define EXT_CSD_STROBE_SUPPORT        184    /* RO */
>>>  #define EXT_CSD_HS_TIMING        185    /* R/W */
>>>  #define EXT_CSD_POWER_CLASS        187    /* R/W */
>>>  #define EXT_CSD_REV            192    /* RO */
>>> @@ -380,12 +381,14 @@ struct _mmc_csd {
>>>  #define EXT_CSD_CARD_TYPE_HS400_1_2V    (1<<7)    /* Card can run at 200MHz DDR, 1.2V */
>>>  #define EXT_CSD_CARD_TYPE_HS400        (EXT_CSD_CARD_TYPE_HS400_1_8V | \
>>>                       EXT_CSD_CARD_TYPE_HS400_1_2V)
>>> +#define EXT_CSD_CARD_TYPE_HS400ES    (1<<8)    /* Card can run at HS400ES */
>>>
>>>  #define EXT_CSD_BUS_WIDTH_1    0    /* Card is in 1 bit mode */
>>>  #define EXT_CSD_BUS_WIDTH_4    1    /* Card is in 4 bit mode */
>>>  #define EXT_CSD_BUS_WIDTH_8    2    /* Card is in 8 bit mode */
>>>  #define EXT_CSD_DDR_BUS_WIDTH_4    5    /* Card is in 4 bit DDR mode */
>>>  #define EXT_CSD_DDR_BUS_WIDTH_8    6    /* Card is in 8 bit DDR mode */
>>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)    /* Enhanced strobe mode */
>>>
>>>  #define EXT_CSD_TIMING_BC    0    /* Backwards compatility */
>>>  #define EXT_CSD_TIMING_HS    1    /* High speed */
>>>
>>
>>
>>
>>
> 
> 



From heiko at sntech.de  Tue May 24 03:17:12 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 24 May 2016 12:17:12 +0200
Subject: [PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
In-Reply-To: <1464073043-4931-1-git-send-email-ykk@rock-chips.com>
References: <1464066147-22734-1-git-send-email-ykk@rock-chips.com>
 <1464073043-4931-1-git-send-email-ykk@rock-chips.com>
Message-ID: <6183955.XzKjc41sjW@phil>

Am Dienstag, 24. Mai 2016, 14:57:23 schrieb Yakir Yang:
> RK3399 and RK3288 shared the same eDP IP controller, only some light
> difference with VOP configure and GRF configure.
> 
> Signed-off-by: Yakir Yang <ykk at rock-chips.com>
> ---
> Changes in v2:
> - rebase with drm-next, fix some conflicts
> 
>  .../bindings/display/bridge/analogix_dp.txt        |  1 +
>  .../display/rockchip/analogix_dp-rockchip.txt      |  2 +-
>  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 36
> ++++++++++++++++++++-- include/drm/bridge/analogix_dp.h                  
> |  1 +
>  4 files changed, 37 insertions(+), 3 deletions(-)
> 
> diff --git
> a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
> b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt index
> 4f2ba8c..4a0f4f7 100644
> --- a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
> +++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
> @@ -5,6 +5,7 @@ Required properties for dp-controller:
>  		platform specific such as:
>  		 * "samsung,exynos5-dp"
>  		 * "rockchip,rk3288-dp"
> +		 * "rockchip,rk3399-edp"

the cleanlines-freak in my likes to know if there is a difference between 
the rk3399 being called -edp here and -dp on the rk3288 :-)

[...]

> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 29c4105..d5d4e04
> 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -148,6 +148,10 @@ rockchip_dp_drm_encoder_atomic_check(struct
> drm_encoder *encoder, struct drm_connector_state *conn_state)
>  {
>  	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
> +	struct rockchip_dp_device *dp = to_dp(encoder);
> +	int ret;
> +
> +	s->output_type = DRM_MODE_CONNECTOR_eDP;
> 
>  	/*
>  	 * FIXME(Yakir): driver should configure the CRTC output video
> @@ -162,8 +166,27 @@ rockchip_dp_drm_encoder_atomic_check(struct
> drm_encoder *encoder, * But if I configure CTRC to RGBaaa, and eDP driver
> still keep * RGB666 input video mode, then screen would works prefect.
>  	 */
> -	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
> -	s->output_type = DRM_MODE_CONNECTOR_eDP;
> +
> +	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
> +	if (ret < 0)
> +		return;

this needs a value returned (probably ret), otherwise you create a 
warning: ?return? with no value, in function returning non-void

drm_of_encoder_active_endpoint_id also always returns -EINVAL on rk3288-
veyron-jerry because encoder->crtc is unset in 
drm_of_encoder_active_endpoint and that breaks display output right now.

Looking through drm code it seems only two functions would set encoder->crtc
- drm_atomic_helper_update_legacy_modeset_state
- drm_crtc_helper_set_config

drm_crtc_helper_set_config callback got dropped in the atomic-conversion and 
the other sounds to be somewhat in the legacy area.

After that drm-internals get a bit confusing.


Heiko


From jh80.chung at samsung.com  Tue May 24 03:20:08 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Tue, 24 May 2016 19:20:08 +0900
Subject: [PATCH v5 2/5] mmc: core: add mmc-hs400-enhanced-strobe support
In-Reply-To: <1463976823-29739-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <CGME20160523041400epcas1p479b50d4a8b5e8e0464657225c164c327@epcas1p4.samsung.com>
 <1463976823-29739-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <57442AD8.6030708@samsung.com>

On 05/23/2016 01:13 PM, Shawn Lin wrote:
> This patch introduce mmc-hs400-enhanced-strobe for platforms
> which want to enable enhanced strobe function from DT if the
> mmc host controller claims to support enhanced strobe.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

Tested-by: Jaehoon Chung <jh80.chung at samsung.com>

Best Regards,
Jaehoon Chung

> 
> ---
> 
> Changes in v5:
> - avoid to call hs400_enhanced+_strobe in mmc_set_initial_state
>   if no setting MMC_CAP2_HS400_ES.
> - add Adrian's ack for patch[5/5]
> 
> Changes in v4:
> - check avail_type with EXT_CSD_CARD_TYPE_HS400 instead of
>   card_type
> - check if host support 8-bit when selecting hs400es
> - some minor fix suggested by Douglas and add his review tag
> 
> Changes in v3:
> - remove helper function and shorten cap2 to MMC_CAP2_HS400_ES
> - rename callback to hs400_enhanced_strobe and make it return void
> - add enhanced_strobe in mmc_ios and pass it to hs400_enhanced_strobe
> - disable host's enhanced strobe in mmc_set_initial_state
> - remove bus checking after switching hs400es
> - add new function for hs400es timing selection
> - fix wrong judgement of mmc_card_hs400es
> 
> Changes in v2:
> - switch to HS400ES from Highspeed mode directly
> 
>  drivers/mmc/core/host.c  | 2 ++
>  include/linux/mmc/host.h | 1 +
>  2 files changed, 3 insertions(+)
> 
> diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
> index e0a3ee1..45773e4 100644
> --- a/drivers/mmc/core/host.c
> +++ b/drivers/mmc/core/host.c
> @@ -289,6 +289,8 @@ int mmc_of_parse(struct mmc_host *host)
>  		host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
>  	if (of_property_read_bool(np, "mmc-hs400-1_2v"))
>  		host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
> +	if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
> +		host->caps2 |= MMC_CAP2_HS400_ES;
>  
>  	host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
>  	if (host->dsr_req && (host->dsr & ~0xffff)) {
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 85800b4..2a06fb0 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -302,6 +302,7 @@ struct mmc_host {
>  #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
>  #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18)	/* No physical write protect pin, assume that card is always read-write */
>  #define MMC_CAP2_NO_SDIO	(1 << 19)	/* Do not send SDIO commands during initialization */
> +#define MMC_CAP2_HS400_ES	(1 << 20)	/* Host supports enhanced strobe */
>  
>  	mmc_pm_flag_t		pm_caps;	/* supported pm features */
>  
> 



From jh80.chung at samsung.com  Tue May 24 03:20:23 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Tue, 24 May 2016 19:20:23 +0900
Subject: [PATCH v5 4/5] mmc: debugfs: add HS400 enhanced strobe description
In-Reply-To: <1463976844-29821-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <CGME20160523041529epcas1p18362d70632f97a1e0ba15189276a916e@epcas1p1.samsung.com>
 <1463976844-29821-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <57442AE7.5090403@samsung.com>

On 05/23/2016 01:14 PM, Shawn Lin wrote:
> We introduce HS400 with enhanced strobe function, so we need
> to add it for debug show.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

Tested-by: Jaehoon Chung <jh80.chung at samsung.com>

Best Regards,
Jaehoon Chung

> ---
> 
> Changes in v5: None
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/mmc/core/debugfs.c | 4 +++-
>  1 file changed, 3 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
> index 9382a57..51d7c38 100644
> --- a/drivers/mmc/core/debugfs.c
> +++ b/drivers/mmc/core/debugfs.c
> @@ -148,7 +148,9 @@ static int mmc_ios_show(struct seq_file *s, void *data)
>  		str = "mmc HS200";
>  		break;
>  	case MMC_TIMING_MMC_HS400:
> -		str = "mmc HS400";
> +		mmc_card_hs400es(host->card) ?
> +			(str = "mmc HS400 enhanced strobe") :
> +			(str = "mmc HS400");
>  		break;
>  	default:
>  		str = "invalid";
> 



From shawn.lin at rock-chips.com  Tue May 24 03:25:35 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Tue, 24 May 2016 18:25:35 +0800
Subject: [PATCH v5 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <574429DF.1000501@samsung.com>
References: <1463976789-29618-1-git-send-email-shawn.lin@rock-chips.com>
 <CGME20160523041529epcas1p3ab7a79120c0ef135fbca109eede66883@epcas1p3.samsung.com>
 <1463976835-29780-1-git-send-email-shawn.lin@rock-chips.com>
 <574425A3.6090303@samsung.com>
 <1f67fa2e-9a14-819d-8d75-3b35be819f0d@rock-chips.com>
 <574429DF.1000501@samsung.com>
Message-ID: <53532571-a8c3-8916-4e98-fd497e37a3ae@rock-chips.com>

? 2016/5/24 18:15, Jaehoon Chung ??:
> On 05/24/2016 07:11 PM, Shawn Lin wrote:
>> ? 2016/5/24 17:57, Jaehoon Chung ??:
>>> On 05/23/2016 01:13 PM, Shawn Lin wrote:
>>>> Controllers use data strobe line to latch data from devices
>>>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>>>> introduces enhanced strobe mode for latching cmd response from
>>>> emmc devices to host controllers. This new feature is optional,
>>>> so it depends both on device's cap and host's cap to decide
>>>> whether to use it or not.
>>>>

[...]

>
> Ok. I have tested with my exynos board. It's working fine.
>
> Tested-by: Jaehoon Chung <jh80.chung at samsung.com>
> Reviewed-by: Jaehoon Chung <jh80.chung at samsung.com>
>

Thanks for your test and review, Jaehoon.

> Best Regards,
> Jaehoon Chung
>



-- 
Best Regards
Shawn Lin



From javi.merino at arm.com  Tue May 24 05:57:42 2016
From: javi.merino at arm.com (Javi Merino)
Date: Tue, 24 May 2016 13:57:42 +0100
Subject: [PATCH v2 1/5] thermal: Add support for hardware-tracked trip
 points
In-Reply-To: <1462268013-14992-2-git-send-email-wxt@rock-chips.com>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
 <1462268013-14992-2-git-send-email-wxt@rock-chips.com>
Message-ID: <20160524125741.GA8979@e104805>

On Tue, May 03, 2016 at 05:33:29PM +0800, Caesar Wang wrote:
> From: Sascha Hauer <s.hauer at pengutronix.de>
> 
> This adds support for hardware-tracked trip points to the device tree
> thermal sensor framework.
> 
> The framework supports an arbitrary number of trip points. Whenever
> the current temperature is updated, the trip points immediately
> below and above the current temperature are found. A .set_trips
> callback is then called with the temperatures. If there is no trip
> point above or below the current temperature, the passed trip
> temperature will be -INT_MAX or INT_MAX respectively. In this callback,
> the driver should program the hardware such that it is notified
> when either of these trip points are triggered. When a trip point
> is triggered, the driver should call `thermal_zone_device_update'
> for the respective thermal zone. This will cause the trip points
> to be updated again.
> 
> If .set_trips is not implemented, the framework behaves as before.
> 
> This patch is based on an earlier version from Mikko Perttunen
> <mikko.perttunen at kapsi.fi>
> 
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Zhang Rui <rui.zhang at intel.com>
> Cc: Eduardo Valentin <edubezval at gmail.com>
> Cc: linux-pm at vger.kernel.org
> 
> ---
> 
> Changes in v2:
> - update the sysfs-api.txt for set_trips
> 
>  Documentation/thermal/sysfs-api.txt |  7 +++++
>  drivers/thermal/thermal_core.c      | 52 +++++++++++++++++++++++++++++++++++++
>  include/linux/thermal.h             |  3 +++
>  3 files changed, 62 insertions(+)
> 
> diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
> index efc3f3d..75d8838 100644
> --- a/Documentation/thermal/sysfs-api.txt
> +++ b/Documentation/thermal/sysfs-api.txt
> @@ -49,6 +49,9 @@ temperature) and throttle appropriate devices.
>  	.bind: bind the thermal zone device with a thermal cooling device.
>  	.unbind: unbind the thermal zone device with a thermal cooling device.
>  	.get_temp: get the current temperature of the thermal zone.
> +	.set_trips: set the trip points window. Whenever the current temperature
> +		    is updated, the trip points immediately below and above the
> +		    current temperature are found.
>  	.get_mode: get the current mode (enabled/disabled) of the thermal zone.
>  	    - "enabled" means the kernel thermal management is enabled.
>  	    - "disabled" will prevent kernel thermal driver action upon trip points
> @@ -95,6 +98,10 @@ temperature) and throttle appropriate devices.
>  			get_temp:	a pointer to a function that reads the
>  					sensor temperature. This is mandatory
>  					callback provided by sensor driver.
> +			set_trips:      a pointer to a function that sets a
> +					temperature window. When this window is
> +					left the driver must inform the thermal
> +					core via thermal_zone_device_update.
>  			get_trend: 	a pointer to a function that reads the
>  					sensor temperature trend.
>  			set_emul_temp:	a pointer to a function that sets
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index 5133cd1..e5bfbd3 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -520,6 +520,51 @@ exit:
>  }
>  EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
>  
> +static void thermal_zone_set_trips(struct thermal_zone_device *tz)
> +{
> +	int low = -INT_MAX;
> +	int high = INT_MAX;
> +	int trip_temp, hysteresis;
> +	int temp = tz->temperature;
> +	int i, ret;
> +
> +	if (!tz->ops->set_trips)
> +		return;
> +
> +	for (i = 0; i < tz->trips; i++) {
> +		int trip_low;
> +
> +		tz->ops->get_trip_temp(tz, i, &trip_temp);
> +		tz->ops->get_trip_hyst(tz, i, &hysteresis);
> +
> +		trip_low = trip_temp - hysteresis;
> +
> +		if (trip_low < temp && trip_low > low)
> +			low = trip_low;
> +
> +		if (trip_temp > temp && trip_temp < high)
> +			high = trip_temp;
> +	}
> +
> +	/* No need to change trip points */
> +	if (tz->prev_low_trip == low && tz->prev_high_trip == high)
> +		return;
> +
> +	tz->prev_low_trip = low;
> +	tz->prev_high_trip = high;
> +
> +	dev_dbg(&tz->device, "new temperature boundaries: %d < x < %d\n",
> +			low, high);
> +
> +	/*
> +	 * Set a temperature window. When this window is left the driver
> +	 * must inform the thermal core via thermal_zone_device_update.
> +	 */
> +	ret = tz->ops->set_trips(tz, low, high);
> +	if (ret)
> +		dev_err(&tz->device, "Failed to set trips: %d\n", ret);

This function can be called at the same time from multiple places so
it should be reentrant.  I think you should call mutex_lock(tz->lock)
before "if (tz->prev_low_trip == low && ..." and unlock it here.

> +}
> +
>  static void update_temperature(struct thermal_zone_device *tz)
>  {
>  	int temp, ret;
> @@ -569,6 +614,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
>  
>  	update_temperature(tz);
>  
> +	thermal_zone_set_trips(tz);
> +
>  	for (count = 0; count < tz->trips; count++)
>  		handle_thermal_trip(tz, count);
>  }
> @@ -754,6 +801,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
>  	 */
>  	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
>  
> +	if (!ret)
> +		thermal_zone_set_trips(tz);
> +

You should add a similar call to thermal_zone_set_trips() in trip_point_temp_store()

>  	return ret ? ret : count;
>  }
>  
> @@ -1843,6 +1893,8 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
>  	tz->trips = trips;
>  	tz->passive_delay = passive_delay;
>  	tz->polling_delay = polling_delay;
> +	tz->prev_low_trip = INT_MAX;
> +	tz->prev_high_trip = -INT_MAX;
>  	/* A new thermal zone needs to be updated anyway. */
>  	atomic_set(&tz->need_update, 1);
>  
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index e45abe7..e258359 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -98,6 +98,7 @@ struct thermal_zone_device_ops {
>  	int (*unbind) (struct thermal_zone_device *,
>  		       struct thermal_cooling_device *);
>  	int (*get_temp) (struct thermal_zone_device *, int *);
> +	int (*set_trips) (struct thermal_zone_device *, int, int);
>  	int (*get_mode) (struct thermal_zone_device *,
>  			 enum thermal_device_mode *);
>  	int (*set_mode) (struct thermal_zone_device *,
> @@ -199,6 +200,8 @@ struct thermal_zone_device {
>  	int last_temperature;
>  	int emul_temperature;
>  	int passive;
> +	int prev_low_trip;
> +	int prev_high_trip;

Please document these fields in the kerneldoc comment before struct
thermal_zone_device.

>  	unsigned int forced_passive;
>  	atomic_t need_update;
>  	struct thermal_zone_device_ops *ops;

Cheers,
Javi


From javi.merino at arm.com  Tue May 24 06:01:39 2016
From: javi.merino at arm.com (Javi Merino)
Date: Tue, 24 May 2016 14:01:39 +0100
Subject: [PATCH v2 2/5] thermal: of: implement .set_trips for device tree
 thermal zones
In-Reply-To: <1462268013-14992-3-git-send-email-wxt@rock-chips.com>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
 <1462268013-14992-3-git-send-email-wxt@rock-chips.com>
Message-ID: <20160524130139.GB8979@e104805>

On Tue, May 03, 2016 at 05:33:30PM +0800, Caesar Wang wrote:
> From: Sascha Hauer <s.hauer at pengutronix.de>
> 
> This patch implemnets .set_trips for device tree thermal zones.
> As the hardware-tracked trip points is supported by thermal core patch[0].
> 
> patch[0]
> "thermal: Add support for hardware-tracked trip points".
> 
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Zhang Rui <rui.zhang at intel.com>
> Cc: Eduardo Valentin <edubezval at gmail.com>
> Cc: linux-pm at vger.kernel.org
> 
> ---
> 
> Changes in v2:
> - add the commit in patch[v2 2/5].
> 
>  drivers/thermal/of-thermal.c | 12 ++++++++++++
>  include/linux/thermal.h      |  4 ++++
>  2 files changed, 16 insertions(+)
> 
> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
> index b8e509c..8722e63 100644
> --- a/drivers/thermal/of-thermal.c
> +++ b/drivers/thermal/of-thermal.c
> @@ -101,6 +101,17 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
>  	return data->ops->get_temp(data->sensor_data, temp);
>  }
>  
> +static int of_thermal_set_trips(struct thermal_zone_device *tz,
> +				int low, int high)
> +{
> +	struct __thermal_zone *data = tz->devdata;
> +
> +	if (!data->ops || !data->ops->set_trips)
> +		return -EINVAL;
> +
> +	return data->ops->set_trips(data->sensor_data, low, high);
> +}
> +
>  /**
>   * of_thermal_get_ntrips - function to export number of available trip
>   *			   points.
> @@ -427,6 +438,7 @@ thermal_zone_of_add_sensor(struct device_node *zone,
>  
>  	tzd->ops->get_temp = of_thermal_get_temp;
>  	tzd->ops->get_trend = of_thermal_get_trend;
> +	tzd->ops->set_trips = of_thermal_set_trips;

Why not do it only if ops->set_trips is set?  Something like

	if (ops->set_trips)
		tzd->ops->set_trips = of_thermal_set_trips;

Otherwise, the thermal zone core will calculate the window for all
device tree thermal zones, even if they haven't set the optional
set_trips pointer.

Cheers,
Javi

>  	tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
>  	mutex_unlock(&tzd->lock);
>  
> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
> index e258359..09053eb 100644
> --- a/include/linux/thermal.h
> +++ b/include/linux/thermal.h
> @@ -336,12 +336,16 @@ struct thermal_genl_event {
>   *
>   * Optional:
>   * @get_trend: a pointer to a function that reads the sensor temperature trend.
> + * @set_trips: a pointer to a function that sets a temperature window. When
> + *	       this window is left the driver must inform the thermal core via
> + *	       thermal_zone_device_update.
>   * @set_emul_temp: a pointer to a function that sets sensor emulated
>   *		   temperature.
>   */
>  struct thermal_zone_of_device_ops {
>  	int (*get_temp)(void *, int *);
>  	int (*get_trend)(void *, long *);
> +	int (*set_trips)(void *, int, int);
>  	int (*set_emul_temp)(void *, int);
>  	int (*set_trip_temp)(void *, int, int);
>  };
> -- 
> 1.9.1
> 


From arnd at arndb.de  Tue May 24 06:03:13 2016
From: arnd at arndb.de (Arnd Bergmann)
Date: Tue, 24 May 2016 15:03:13 +0200
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <9836736.6VjP1ug4kE@wuerfel>

On Friday, May 20, 2016 6:29:16 PM CEST Shawn Lin wrote:

> +static int rockchip_pcie_wr_own_conf(struct rockchip_pcie_port *pp,
> +				     int where, int size, u32 val)
> +{
> +	u32 tmp;
> +	int offset;
> +
> +	offset = (where & (~0x3));
> +	tmp = readl(pp->apb_base + PCIE_RC_CONFIG_BASE + offset);
> +	if (size == 4) {
> +		writel(val, pp->apb_base + PCIE_RC_CONFIG_BASE + where);
> +	} else if (size == 2) {
> +		if (where & 0x2)
> +			tmp = ((tmp & 0xffff) | (val << 16));
> +		else
> +			tmp = ((tmp & 0xffff0000) | val);
> +
> +		writel(tmp, pp->apb_base + PCIE_RC_CONFIG_BASE + offset);
> +	} else if (size == 1) {
> +		if ((where & 0x3) == 0)
> +			tmp = ((tmp & (~0xff)) | val);
> +		else if ((where & 0x3) == 1)
> +			tmp = ((tmp & (~0xff00)) | (val << 8));
> +		else if ((where & 0x3) == 2)
> +			tmp = ((tmp & (~0xff0000)) | (val << 16));
> +		else if ((where & 0x3) == 3)
> +			tmp = ((tmp & (~0xff000000)) | (val << 24));
> +
> +		writel(tmp, pp->apb_base + PCIE_RC_CONFIG_BASE + offset);
> +	} else {
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +	}
> +	return PCIBIOS_SUCCESSFUL;
> +}

Why can't you access the individual sub-word registers here?

> +
> +static int rockchip_pcie_rd_other_conf(struct rockchip_pcie_port *pp,
> +				       struct pci_bus *bus, u32 devfn,
> +				       int where, int size, u32 *val)
> +{
> +	u32 busdev;
> +
> +	busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
> +				PCI_FUNC(devfn), where);
> +
> +	if (busdev & (size - 1)) {
> +		*val = 0;
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +	}
> +
> +	if (size == 4) {
> +		*val = readl(pp->reg_base + busdev);
> +	} else if (size == 2) {
> +		*val = readw(pp->reg_base + busdev);
> +	} else if (size == 1) {
> +		*val = readb(pp->reg_base + busdev);
> +	} else {
> +		*val = 0;
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +	}
> +	return PCIBIOS_SUCCESSFUL;
> +}
> +

This looks like the normal ECAM operations, you could just call those.

> +	while (time_before(jiffies, timeout)) {
> +		regmap_read(port->grf, port->pcie_status, &status);
> +		if ((status & (1 << 9))) {
> +			dev_info(port->dev, "pll locked!\n");
> +			err = 0;
> +			break;
> +		}
> +	}

Maybe add an msleep(1) here to avoid busy-looping?


> +	for (reg_no = 0; reg_no < (port->mem_size >> 20); reg_no++) {
> +		err = rockchip_pcie_prog_ob_atu(port, reg_no + 1,
> +						AXI_WRAPPER_MEM_WRITE,
> +						20 - 1,
> +						port->mem_bus_addr +
> +							(reg_no << 20),
> +						0);
> +		if (err) {
> +			dev_err(dev, "Program RC outbound atu failed\n");
> +			return err;
> +		}
> +	}

What if there is more than one outbound memory window, e.g. prefetchable
and non-prefetchable?

Where do you set the I/O window?

> +	err = rockchip_pcie_prog_ib_atu(port, 2, 32 - 1, 0x0, 0);
> +	if (err) {
> +		dev_err(dev, "Program RC inbound atu failed\n");
> +		return err;
> +	}

And this doesn't seem to reflect the DMA ranges.

> +
> +	port->root_bus_nr = port->busn->start;
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		bus = pci_scan_root_bus_msi(port->dev, port->root_bus_nr,
> +					    &rockchip_pcie_ops, port, &res,
> +					    port->msi);
> +	} else {
> +		bus = pci_scan_root_bus(&pdev->dev, 0,
> +					&rockchip_pcie_ops, port, &res);


PCI_MSI is selected unconditionally from Kconfig for this driver, so no
need for the compile-time check here.

> +
> +static int rockchip_pcie_remove(struct platform_device *pdev)
> +{
> +	struct rockchip_pcie_port *port = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(port->hclk_pcie);
> +	clk_disable_unprepare(port->aclk_perf_pcie);
> +	clk_disable_unprepare(port->aclk_pcie);
> +	clk_disable_unprepare(port->clk_pciephy_ref);
> +
> +	return 0;
> +}

You don't seem to remove the child devices here. Have you tried unloading the module?

	Arnd




From javi.merino at arm.com  Tue May 24 06:06:10 2016
From: javi.merino at arm.com (Javi Merino)
Date: Tue, 24 May 2016 14:06:10 +0100
Subject: [PATCH v2 4/5] thermal: bang-bang governor: act on lower trip
 boundary
In-Reply-To: <1462268013-14992-5-git-send-email-wxt@rock-chips.com>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
 <1462268013-14992-5-git-send-email-wxt@rock-chips.com>
Message-ID: <20160524130610.GC8979@e104805>

Ccing Peter Feuerer, author of the bang bang governor.

On Tue, May 03, 2016 at 05:33:32PM +0800, Caesar Wang wrote:
> From: Sascha Hauer <s.hauer at pengutronix.de>
> 
> With interrupt driven thermal zones we pass the lower and upper
> temperature on which shall be acted, so in the governor we have to act on
> the exact lower temperature to be consistent. Otherwise an interrupt maybe
> generated on the exact lower temperature, but the bang bang governor does
> not react since The polling driven zones have to be one step cooler before
> the governor reacts.
> 
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Zhang Rui <rui.zhang at intel.com>
> Cc: Eduardo Valentin <edubezval at gmail.com>
> Cc: linux-pm at vger.kernel.org
> 
> ---
> 
> Changes in v2:
> - Update the commit for patch[v2 4/5].
> 
>  drivers/thermal/gov_bang_bang.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
> index 70836c5..9d1dfea 100644
> --- a/drivers/thermal/gov_bang_bang.c
> +++ b/drivers/thermal/gov_bang_bang.c
> @@ -59,7 +59,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
>  		if (instance->target == 0 && tz->temperature >= trip_temp)
>  			instance->target = 1;
>  		else if (instance->target == 1 &&
> -				tz->temperature < trip_temp - trip_hyst)
> +				tz->temperature <= trip_temp - trip_hyst)
>  			instance->target = 0;
>  
>  		dev_dbg(&instance->cdev->device, "target=%d\n",
> -- 
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 


From heiko at sntech.de  Tue May 24 06:07:52 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 24 May 2016 15:07:52 +0200
Subject: [PATCH 2/3] soc: rockchip: add driver handling grf setup
In-Reply-To: <6a6e87ee-688d-90a3-2407-22847bd80971@rock-chips.com>
References: <1464015539-19521-1-git-send-email-heiko@sntech.de>
 <1464015539-19521-3-git-send-email-heiko@sntech.de>
 <6a6e87ee-688d-90a3-2407-22847bd80971@rock-chips.com>
Message-ID: <7631878.OiMWPcBrqd@phil>

Am Dienstag, 24. Mai 2016, 10:22:09 schrieb Shawn Lin:
> Hi Heiko,
> 
> On 2016/5/23 22:58, Heiko Stuebner wrote:
> > The General Register Files are an area of registers containing a lot
> > of single-bit settings for numerous components as well full components
> > like usbphy control. Therefore all used components are accessed
> > via the syscon provided by the grf nodes or from the sub-devices
> > created through the simple-mfd created from the grf node.
> > 
> > Some settings are not used by anything but will need to be set up
> > according to expectations on the kernel side.
> > 
> > Best example is the force_jtag setting, which defaults to on and
> > results in the soc switching the pin-outputs between jtag and sdmmc
> > automatically depending on the card-detect status. This conflicts
> > heavily with how the dw_mmc driver expects to do its work and also
> > with the clock-controller, which has most likely deactivated the
> > jtag clock due to it being unused.
> 
> I agree we should disable force_jtag for real product. But on my local
> branch we add a callback to parse a tag from cmdline. Sometime it's
> useful for debugging in case of we need to setup JTAG for reproducing
> and comfirming serious issue in which state the CPU cannot reponse to
> any console input or FIQ-debug triggering.
>
> Should we need it for upstream as you move all related code in this
> new driver?  I'm not sure.

This driver really _should not_ become a catchall for settings stuff.
I.e. the jtag/sdmmc switch handles the automatic switching done inside the 
soc based on the card-detect state. Which confuses the dw_mmc driver.

If I'm reading that correctly in the TRM, jtag on Rockchip SoCs is part of 
the coresight infrastructure - in the DAP block.
There are generic drivers + devicetree bindings for (I think most) coresight 
blocks existing now, but I haven't found anything related to the DAP itself.

In theory I'd think real handling of jtag pins/clocks should be done 
somewhere in that area and and if jtag is to be used,it could then be set up 
using in-kernel mechanics, like disabling sdmmc that claims the shared pins 
and enabling the jtag pinctrl and clocks.

This could even be doable at runtime via devicetree overlays.


Most likely way out of scope for now, but that is where I would imagine this 
stuff to be.

Heiko


From peter at piie.net  Tue May 24 06:11:59 2016
From: peter at piie.net (Peter Feuerer)
Date: Tue, 24 May 2016 13:11:59 +0000
Subject: [PATCH v2 4/5] thermal: bang-bang governor: act on lower trip
 boundary
In-Reply-To: <20160524130610.GC8979@e104805>
References: <20160524130610.GC8979@e104805>
 <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
 <1462268013-14992-5-git-send-email-wxt@rock-chips.com>
Message-ID: <16fa68c03a68c215e3b464a03ba57b16@mail.piie.net>

Hi,

24. Mai 2016 15:06 Uhr, "Javi Merino" <javi.merino at arm.com> schrieb:
> Ccing Peter Feuerer, author of the bang bang governor.

thanks, will take care today in the evening.

--peter;


> 
> On Tue, May 03, 2016 at 05:33:32PM +0800, Caesar Wang wrote:
> 
>> From: Sascha Hauer <s.hauer at pengutronix.de>
>> 
>> With interrupt driven thermal zones we pass the lower and upper
>> temperature on which shall be acted, so in the governor we have to act on
>> the exact lower temperature to be consistent. Otherwise an interrupt maybe
>> generated on the exact lower temperature, but the bang bang governor does
>> not react since The polling driven zones have to be one step cooler before
>> the governor reacts.
>> 
>> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>> Cc: Zhang Rui <rui.zhang at intel.com>
>> Cc: Eduardo Valentin <edubezval at gmail.com>
>> Cc: linux-pm at vger.kernel.org
>> 
>> ---
>> 
>> Changes in v2:
>> - Update the commit for patch[v2 4/5].
>> 
>> drivers/thermal/gov_bang_bang.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>> 
>> diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
>> index 70836c5..9d1dfea 100644
>> --- a/drivers/thermal/gov_bang_bang.c
>> +++ b/drivers/thermal/gov_bang_bang.c
>> @@ -59,7 +59,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
>> if (instance->target == 0 && tz->temperature >= trip_temp)
>> instance->target = 1;
>> else if (instance->target == 1 &&
>> - tz->temperature < trip_temp - trip_hyst)
>> + tz->temperature <= trip_temp - trip_hyst)
>> instance->target = 0;
>> 
>> dev_dbg(&instance->cdev->device, "target=%d\n",
>> --
>> 1.9.1
>> 
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html


From broonie at kernel.org  Tue May 24 09:25:59 2016
From: broonie at kernel.org (Mark Brown)
Date: Tue, 24 May 2016 17:25:59 +0100
Subject: Applied "ASoC: rockchip: i2s: rename I2S_CKR_TRCM_TX/RXSHARE to
 I2S_CKR_TRCM_TX/RXONLY" to the asoc tree
In-Reply-To: <1464061667-16477-1-git-send-email-zhengxing@rock-chips.com>
Message-ID: <E1b5F9b-0003ax-0p@debutante>

The patch

   ASoC: rockchip: i2s: rename I2S_CKR_TRCM_TX/RXSHARE to I2S_CKR_TRCM_TX/RXONLY

has been applied to the asoc tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From 7ec4a1c34a190297540626dfa240dc033beca196 Mon Sep 17 00:00:00 2001
From: Sugar Zhang <sugar.zhang at rock-chips.com>
Date: Tue, 24 May 2016 11:47:46 +0800
Subject: [PATCH] ASoC: rockchip: i2s: rename I2S_CKR_TRCM_TX/RXSHARE to
 I2S_CKR_TRCM_TX/RXONLY

this patch make it more reasonable and readable, because when we chose
I2S_CKR_TRCM_TXONLY, we only output clk_lrck_tx, and hardware need to
confirm this signal is wired to external codec lrck_tx/rx at the same time.

for convenience, we just handle lrck_txonly if we enable symmetric_rates
in driver and dai_link. otherwise, we use the separate lrck_tx/rx.

Signed-off-by: Sugar Zhang <sugar.zhang at rock-chips.com>
Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 sound/soc/rockchip/rockchip_i2s.c | 4 ++--
 sound/soc/rockchip/rockchip_i2s.h | 4 ++--
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/sound/soc/rockchip/rockchip_i2s.c b/sound/soc/rockchip/rockchip_i2s.c
index d4f7eac5cfd4..ca1cf3b085a4 100644
--- a/sound/soc/rockchip/rockchip_i2s.c
+++ b/sound/soc/rockchip/rockchip_i2s.c
@@ -316,8 +316,8 @@ static int rockchip_i2s_hw_params(struct snd_pcm_substream *substream,
 			   I2S_DMACR_RDL(16));
 
 	val = I2S_CKR_TRCM_TXRX;
-	if (dai->driver->symmetric_rates || rtd->dai_link->symmetric_rates)
-		val = I2S_CKR_TRCM_TXSHARE;
+	if (dai->driver->symmetric_rates && rtd->dai_link->symmetric_rates)
+		val = I2S_CKR_TRCM_TXONLY;
 
 	regmap_update_bits(i2s->regmap, I2S_CKR,
 			   I2S_CKR_TRCM_MASK,
diff --git a/sound/soc/rockchip/rockchip_i2s.h b/sound/soc/rockchip/rockchip_i2s.h
index 8e239d301bc7..31f11fd25393 100644
--- a/sound/soc/rockchip/rockchip_i2s.h
+++ b/sound/soc/rockchip/rockchip_i2s.h
@@ -81,8 +81,8 @@
 #define I2S_CKR_TRCM_SHIFT	28
 #define I2S_CKR_TRCM(x)	(x << I2S_CKR_TRCM_SHIFT)
 #define I2S_CKR_TRCM_TXRX	(0 << I2S_CKR_TRCM_SHIFT)
-#define I2S_CKR_TRCM_TXSHARE	(1 << I2S_CKR_TRCM_SHIFT)
-#define I2S_CKR_TRCM_RXSHARE	(2 << I2S_CKR_TRCM_SHIFT)
+#define I2S_CKR_TRCM_TXONLY	(1 << I2S_CKR_TRCM_SHIFT)
+#define I2S_CKR_TRCM_RXONLY	(2 << I2S_CKR_TRCM_SHIFT)
 #define I2S_CKR_TRCM_MASK	(3 << I2S_CKR_TRCM_SHIFT)
 #define I2S_CKR_MSS_SHIFT	27
 #define I2S_CKR_MSS_MASTER	(0 << I2S_CKR_MSS_SHIFT)
-- 
2.8.1



From peter at piie.net  Tue May 24 10:34:58 2016
From: peter at piie.net (Peter Feuerer)
Date: Tue, 24 May 2016 17:34:58 +0000
Subject: [PATCH v2 4/5] thermal: bang-bang governor: act on lower trip
 boundary
In-Reply-To: <20160524130610.GC8979@e104805>
References: <20160524130610.GC8979@e104805>
 <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
 <1462268013-14992-5-git-send-email-wxt@rock-chips.com>
Message-ID: <a942e788aa285dcf88db38c6d03a36ce@mail.piie.net>

Hi,

24. Mai 2016 15:06 Uhr, "Javi Merino" <javi.merino at arm.com> schrieb:
> Ccing Peter Feuerer, author of the bang bang governor.
> 
> On Tue, May 03, 2016 at 05:33:32PM +0800, Caesar Wang wrote:
> 
>> From: Sascha Hauer <s.hauer at pengutronix.de>
>> 
>> With interrupt driven thermal zones we pass the lower and upper
>> temperature on which shall be acted, so in the governor we have to act on
>> the exact lower temperature to be consistent. Otherwise an interrupt maybe
>> generated on the exact lower temperature, but the bang bang governor does
>> not react since The polling driven zones have to be one step cooler before
>> the governor reacts.
>> 
>> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>> Cc: Zhang Rui <rui.zhang at intel.com>
>> Cc: Eduardo Valentin <edubezval at gmail.com>
>> Cc: linux-pm at vger.kernel.org

Acked-by: Peter Feuerer <peter at piie.net>


>> 
>> ---
>> 
>> Changes in v2:
>> - Update the commit for patch[v2 4/5].
>> 
>> drivers/thermal/gov_bang_bang.c | 2 +-
>> 1 file changed, 1 insertion(+), 1 deletion(-)
>> 
>> diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
>> index 70836c5..9d1dfea 100644
>> --- a/drivers/thermal/gov_bang_bang.c
>> +++ b/drivers/thermal/gov_bang_bang.c
>> @@ -59,7 +59,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
>> if (instance->target == 0 && tz->temperature >= trip_temp)
>> instance->target = 1;
>> else if (instance->target == 1 &&
>> - tz->temperature < trip_temp - trip_hyst)
>> + tz->temperature <= trip_temp - trip_hyst)
>> instance->target = 0;
>> 
>> dev_dbg(&instance->cdev->device, "target=%d\n",
>> --
>> 1.9.1
>> 
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html


From dianders at chromium.org  Tue May 24 11:12:20 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 24 May 2016 11:12:20 -0700
Subject: [PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
In-Reply-To: <6183955.XzKjc41sjW@phil>
References: <1464066147-22734-1-git-send-email-ykk@rock-chips.com>
 <1464073043-4931-1-git-send-email-ykk@rock-chips.com>
 <6183955.XzKjc41sjW@phil>
Message-ID: <CAD=FV=WH6xYE6UiDxVK=cLnhoHnCvecSL4tk7FUVAnkGbQ-QOg@mail.gmail.com>

Hi,

On Tue, May 24, 2016 at 3:17 AM, Heiko Stuebner <heiko at sntech.de> wrote:
>> --- a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
>> +++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
>> @@ -5,6 +5,7 @@ Required properties for dp-controller:
>>               platform specific such as:
>>                * "samsung,exynos5-dp"
>>                * "rockchip,rk3288-dp"
>> +              * "rockchip,rk3399-edp"
>
> the cleanlines-freak in my likes to know if there is a difference between
> the rk3399 being called -edp here and -dp on the rk3288 :-)
>
> [...]

If I was a guessing man (which I'm not, but if I was), I'd guess that
this is because on rk3288 there was only one DP port and it was an EDP
port.  ...but since there was only one people just referred to it as
the "DP" port and that was codified in the bindings.  On rk3399 there
are two ports: one EDP and one DP.  All of a sudden we need to
differentiate.

Any better suggestions for how to deal with that?


-Doug


From heiko at sntech.de  Tue May 24 11:23:48 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Tue, 24 May 2016 20:23:48 +0200
Subject: [PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
In-Reply-To: <CAD=FV=WH6xYE6UiDxVK=cLnhoHnCvecSL4tk7FUVAnkGbQ-QOg@mail.gmail.com>
References: <1464066147-22734-1-git-send-email-ykk@rock-chips.com>
 <6183955.XzKjc41sjW@phil>
 <CAD=FV=WH6xYE6UiDxVK=cLnhoHnCvecSL4tk7FUVAnkGbQ-QOg@mail.gmail.com>
Message-ID: <8988677.GHLC4rSfsM@phil>

Am Dienstag, 24. Mai 2016, 11:12:20 schrieb Doug Anderson:
> Hi,
> 
> On Tue, May 24, 2016 at 3:17 AM, Heiko Stuebner <heiko at sntech.de> wrote:
> >> --- a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
> >> +++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
> >> 
> >> @@ -5,6 +5,7 @@ Required properties for dp-controller:
> >>               platform specific such as:
> >>                * "samsung,exynos5-dp"
> >>                * "rockchip,rk3288-dp"
> >> 
> >> +              * "rockchip,rk3399-edp"
> > 
> > the cleanlines-freak in my likes to know if there is a difference
> > between
> > the rk3399 being called -edp here and -dp on the rk3288 :-)
> > 
> > [...]
> 
> If I was a guessing man (which I'm not, but if I was), I'd guess that
> this is because on rk3288 there was only one DP port and it was an EDP
> port.  ...but since there was only one people just referred to it as
> the "DP" port and that was codified in the bindings.  On rk3399 there
> are two ports: one EDP and one DP.  All of a sudden we need to
> differentiate.
> 
> Any better suggestions for how to deal with that?

nope - everything as it should be in that regard then - the rk3288-dp is 
permanent now anyway.

But it looks like I'm sort of blind blind and only now have seen the 
separate DP controller chapter in the TRM (probably because I somehow didn't 
expect a second controller).


From romieu at fr.zoreil.com  Tue May 24 12:02:35 2016
From: romieu at fr.zoreil.com (Francois Romieu)
Date: Tue, 24 May 2016 21:02:35 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <5743A9DD.8010202@gmx.de>
References: <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com>
 <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm> <5740E82F.8040903@gmx.de>
 <20160522091742.GA8681@debian-dorm> <57419853.9050701@gmx.de>
 <20160522223659.GB5086@electric-eye.fr.zoreil.com>
 <5743A9DD.8010202@gmx.de>
Message-ID: <20160524190235.GA31006@electric-eye.fr.zoreil.com>

Lino Sanfilippo <LinoSanfilippo at gmx.de> :
[...]
> I dont agree here. A dma_wmb would have an effect to "data" and "info", yes,
> but it would have absolutely no effect to skb_tx_timestamp(), since there
> is no dma access involved here. In fact skb_tx_timestamp() could probably
> be even reordered to appear after the dma_wmb.
>
> Anyway, there is the wmb() directly after the assignment to "info". _This_
> barrier  should ensure that skb_tx_timestamp() (along with a flush of data
> and info to DMA) is executed before "txbd_curr" is advanced.
> This means that the corresponding skb cant be freed prematurely by tx_clean().

The concern here is about sending adequate PTP payload on the network.

skb_tx_timestamp() is used for network clock synchronization. Some extra
information must be transmitted. Be it through direct payload change
or through indirect control, it _is_ related to dma.

Several (most ?) skb_tx_timestamp() misuses blur the picture: CPU vs device
sync is of course way below the radar when the driver crashes because of
plain use-after-free skb_tx_timestamp() :o/

-- 
Ueimor


From LinoSanfilippo at gmx.de  Tue May 24 16:56:20 2016
From: LinoSanfilippo at gmx.de (Lino Sanfilippo)
Date: Wed, 25 May 2016 01:56:20 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <5743A9DD.8010202@gmx.de>
References: <20160517.142456.2247845107325931733.davem@davemloft.net>
 <20160518000153.GA21757@electric-eye.fr.zoreil.com> <573CD09D.1060307@gmx.de>
 <20160518225529.GA18671@electric-eye.fr.zoreil.com> <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm> <5740E82F.8040903@gmx.de>
 <20160522091742.GA8681@debian-dorm> <57419853.9050701@gmx.de>
 <20160522223659.GB5086@electric-eye.fr.zoreil.com> <5743A9DD.8010202@gmx.de>
Message-ID: <5744EA24.7060806@gmx.de>

Francois, Shuyu,

this is the patch with the discussed changes.

Shuyu it would be great if you could test this one. If it passes
and there are no further objections I will resend it as a regular patch
(including commit message, etc.) to the mailing list.


diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
index a3a9392..ec656b3 100644
--- a/drivers/net/ethernet/arc/emac_main.c
+++ b/drivers/net/ethernet/arc/emac_main.c
@@ -153,18 +153,29 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 {
 	struct arc_emac_priv *priv = netdev_priv(ndev);
 	struct net_device_stats *stats = &ndev->stats;
+	unsigned int curr = priv->txbd_curr;
 	unsigned int i;
 
+	/* Make sure buffers and txbd_curr are consistent */
+	smp_rmb();
+
 	for (i = 0; i < TX_BD_NUM; i++) {
 		unsigned int *txbd_dirty = &priv->txbd_dirty;
 		struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
 		struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
-		struct sk_buff *skb = tx_buff->skb;
-		unsigned int info = le32_to_cpu(txbd->info);
+		unsigned int info;
+		struct sk_buff *skb;
 
-		if ((info & FOR_EMAC) || !txbd->data || !skb)
+		if (*txbd_dirty == curr)
 			break;
 
+		info = le32_to_cpu(txbd->info);
+
+		if (info & FOR_EMAC)
+			break;
+
+		skb = tx_buff->skb;
+
 		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
 			stats->tx_errors++;
 			stats->tx_dropped++;
@@ -195,8 +206,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
 		*txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;
 	}
 
-	/* Ensure that txbd_dirty is visible to tx() before checking
-	 * for queue stopped.
+	/* Ensure that txbd_dirty is visible to tx() and we see the most recent
+	 * value for txbd_curr.
 	 */
 	smp_mb();
 
@@ -680,27 +691,24 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
 	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
 
 	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
-
-	/* Make sure pointer to data buffer is set */
-	wmb();
+	priv->tx_buff[*txbd_curr].skb = skb;
 
 	skb_tx_timestamp(skb);
 
 	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
 
-	/* Make sure info word is set */
+	/* 1. Make sure that with respect to tx_clean everything is set up
+	 * properly before we advance txbd_curr.
+	 * 2. Make sure writes to DMA descriptors are completed before we inform
+	 * the hardware.
+	 */
 	wmb();
 
-	priv->tx_buff[*txbd_curr].skb = skb;
-
 	/* Increment index to point to the next BD */
 	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
 
-	/* Ensure that tx_clean() sees the new txbd_curr before
-	 * checking the queue status. This prevents an unneeded wake
-	 * of the queue in tx_clean().
-	 */
-	smp_mb();
+	/* Ensure tx_clean() sees the updated value of txbd_curr */
+	smp_wmb();
 
 	if (!arc_emac_tx_avail(priv)) {
 		netif_stop_queue(ndev);
-- 
1.9.1






From caesar.upstream at gmail.com  Tue May 24 20:27:24 2016
From: caesar.upstream at gmail.com (Caesar Wang)
Date: Wed, 25 May 2016 11:27:24 +0800
Subject: [PATCH v2 1/5] thermal: Add support for hardware-tracked trip
 points
In-Reply-To: <20160524125741.GA8979@e104805>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
 <1462268013-14992-2-git-send-email-wxt@rock-chips.com>
 <20160524125741.GA8979@e104805>
Message-ID: <57451B9C.7070705@gmail.com>

Hi Javi,

Thanks your reviewing.

On 2016?05?24? 20:57, Javi Merino wrote:
> On Tue, May 03, 2016 at 05:33:29PM +0800, Caesar Wang wrote:
>> From: Sascha Hauer <s.hauer at pengutronix.de>
>>
>> This adds support for hardware-tracked trip points to the device tree
>> thermal sensor framework.
>>
>> The framework supports an arbitrary number of trip points. Whenever
>> the current temperature is updated, the trip points immediately
>> below and above the current temperature are found. A .set_trips
>> callback is then called with the temperatures. If there is no trip
>> point above or below the current temperature, the passed trip
>> temperature will be -INT_MAX or INT_MAX respectively. In this callback,
>> the driver should program the hardware such that it is notified
>> when either of these trip points are triggered. When a trip point
>> is triggered, the driver should call `thermal_zone_device_update'
>> for the respective thermal zone. This will cause the trip points
>> to be updated again.
>>
>> If .set_trips is not implemented, the framework behaves as before.
>>
>> This patch is based on an earlier version from Mikko Perttunen
>> <mikko.perttunen at kapsi.fi>
>>
>> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>> Cc: Zhang Rui <rui.zhang at intel.com>
>> Cc: Eduardo Valentin <edubezval at gmail.com>
>> Cc: linux-pm at vger.kernel.org
>>
>> ---
>>
>> Changes in v2:
>> - update the sysfs-api.txt for set_trips
>>
>>   Documentation/thermal/sysfs-api.txt |  7 +++++
>>   drivers/thermal/thermal_core.c      | 52 +++++++++++++++++++++++++++++++++++++
>>   include/linux/thermal.h             |  3 +++
>>   3 files changed, 62 insertions(+)
<cut..>
>> +	/*
>> +	 * Set a temperature window. When this window is left the driver
>> +	 * must inform the thermal core via thermal_zone_device_update.
>> +	 */
>> +	ret = tz->ops->set_trips(tz, low, high);
>> +	if (ret)
>> +		dev_err(&tz->device, "Failed to set trips: %d\n", ret);
> This function can be called at the same time from multiple places so
> it should be reentrant.  I think you should call mutex_lock(tz->lock)
> before "if (tz->prev_low_trip == low && ..." and unlock it here.

Sound reasonable, fixes it in next version.

>> +}
>> +
>>   static void update_temperature(struct thermal_zone_device *tz)
>>   {
>>   	int temp, ret;
>> @@ -569,6 +614,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
>>   
>>   	update_temperature(tz);
>>   
>> +	thermal_zone_set_trips(tz);
>> +
>>   	for (count = 0; count < tz->trips; count++)
>>   		handle_thermal_trip(tz, count);
>>   }
>> @@ -754,6 +801,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
>>   	 */
>>   	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
>>   
>> +	if (!ret)
>> +		thermal_zone_set_trips(tz);
>> +
> You should add a similar call to thermal_zone_set_trips() in trip_point_temp_store()

No, this patch has been done.

if you see the linux next kernel.
72f3ada UPSTREAM: thermal: trip_point_temp_store() calls 
thermal_zone_device_update()

--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -733,8 +733,12 @@ trip_point_temp_store(struct device *dev, struct 
device_attribute *attr,
return -EINVAL;

ret = tz->ops->set_trip_temp(tz, trip, temperature);
+ if (ret)
+ return ret;

- return ret ? ret : count;
+ thermal_zone_device_update(tz);
+
+ return count;
}

So the "thermal_zone_set_trips(tz)" have been set in 
thermal_zone_device_update.

>>   	return ret ? ret : count;
>>   }
>>   
>> @@ -1843,6 +1893,8 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
>>   	tz->trips = trips;
>>   	tz->passive_delay = passive_delay;
>>   	tz->polling_delay = polling_delay;
>> +	tz->prev_low_trip = INT_MAX;
>> +	tz->prev_high_trip = -INT_MAX;
>>   	/* A new thermal zone needs to be updated anyway. */
>>   	atomic_set(&tz->need_update, 1);
>>   
>> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
>> index e45abe7..e258359 100644
>> --- a/include/linux/thermal.h
>> +++ b/include/linux/thermal.h
>> @@ -98,6 +98,7 @@ struct thermal_zone_device_ops {
>>   	int (*unbind) (struct thermal_zone_device *,
>>   		       struct thermal_cooling_device *);
>>   	int (*get_temp) (struct thermal_zone_device *, int *);
>> +	int (*set_trips) (struct thermal_zone_device *, int, int);
>>   	int (*get_mode) (struct thermal_zone_device *,
>>   			 enum thermal_device_mode *);
>>   	int (*set_mode) (struct thermal_zone_device *,
>> @@ -199,6 +200,8 @@ struct thermal_zone_device {
>>   	int last_temperature;
>>   	int emul_temperature;
>>   	int passive;
>> +	int prev_low_trip;
>> +	int prev_high_trip;
> Please document these fields in the kerneldoc comment before struct
> thermal_zone_device.

Okay, done.

Thanks!

-
Caesar
>>   	unsigned int forced_passive;
>>   	atomic_t need_update;
>>   	struct thermal_zone_device_ops *ops;
> Cheers,
> Javi
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip



From caesar.upstream at gmail.com  Tue May 24 20:28:58 2016
From: caesar.upstream at gmail.com (Caesar Wang)
Date: Wed, 25 May 2016 11:28:58 +0800
Subject: [PATCH v2 2/5] thermal: of: implement .set_trips for device tree
 thermal zones
In-Reply-To: <20160524130139.GB8979@e104805>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
 <1462268013-14992-3-git-send-email-wxt@rock-chips.com>
 <20160524130139.GB8979@e104805>
Message-ID: <57451BFA.4090404@gmail.com>

Hi Javi,

On 2016?05?24? 21:01, Javi Merino wrote:
> On Tue, May 03, 2016 at 05:33:30PM +0800, Caesar Wang wrote:
>> From: Sascha Hauer <s.hauer at pengutronix.de>
>>
>> This patch implemnets .set_trips for device tree thermal zones.
>> As the hardware-tracked trip points is supported by thermal core patch[0].
>>
>> patch[0]
>> "thermal: Add support for hardware-tracked trip points".
>>
>> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>> Cc: Zhang Rui <rui.zhang at intel.com>
>> Cc: Eduardo Valentin <edubezval at gmail.com>
>> Cc: linux-pm at vger.kernel.org
>>
>> ---
>>
>> Changes in v2:
>> - add the commit in patch[v2 2/5].
>>
>>   drivers/thermal/of-thermal.c | 12 ++++++++++++
>>   include/linux/thermal.h      |  4 ++++
>>   2 files changed, 16 insertions(+)
>>
>> diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
>> index b8e509c..8722e63 100644
>> --- a/drivers/thermal/of-thermal.c
>> +++ b/drivers/thermal/of-thermal.c
>> @@ -101,6 +101,17 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
>>   	return data->ops->get_temp(data->sensor_data, temp);
>>   }
>>   
>> +static int of_thermal_set_trips(struct thermal_zone_device *tz,
>> +				int low, int high)
>> +{
>> +	struct __thermal_zone *data = tz->devdata;
>> +
>> +	if (!data->ops || !data->ops->set_trips)
>> +		return -EINVAL;
>> +
>> +	return data->ops->set_trips(data->sensor_data, low, high);
>> +}
>> +
>>   /**
>>    * of_thermal_get_ntrips - function to export number of available trip
>>    *			   points.
>> @@ -427,6 +438,7 @@ thermal_zone_of_add_sensor(struct device_node *zone,
>>   
>>   	tzd->ops->get_temp = of_thermal_get_temp;
>>   	tzd->ops->get_trend = of_thermal_get_trend;
>> +	tzd->ops->set_trips = of_thermal_set_trips;
> Why not do it only if ops->set_trips is set?  Something like
>
> 	if (ops->set_trips)
> 		tzd->ops->set_trips = of_thermal_set_trips;
>
> Otherwise, the thermal zone core will calculate the window for all
> device tree thermal zones, even if they haven't set the optional
> set_trips pointer.

Hmm, agree it in here.
fixes in next version.

> Cheers,
> Javi
>
>>   	tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
>>   	mutex_unlock(&tzd->lock);
>>   
>> diff --git a/include/linux/thermal.h b/include/linux/thermal.h
>> index e258359..09053eb 100644
>> --- a/include/linux/thermal.h
>> +++ b/include/linux/thermal.h
>> @@ -336,12 +336,16 @@ struct thermal_genl_event {
>>    *
>>    * Optional:
>>    * @get_trend: a pointer to a function that reads the sensor temperature trend.
>> + * @set_trips: a pointer to a function that sets a temperature window. When
>> + *	       this window is left the driver must inform the thermal core via
>> + *	       thermal_zone_device_update.
>>    * @set_emul_temp: a pointer to a function that sets sensor emulated
>>    *		   temperature.
>>    */
>>   struct thermal_zone_of_device_ops {
>>   	int (*get_temp)(void *, int *);
>>   	int (*get_trend)(void *, long *);
>> +	int (*set_trips)(void *, int, int);
>>   	int (*set_emul_temp)(void *, int);
>>   	int (*set_trip_temp)(void *, int, int);
>>   };
>> -- 
>> 1.9.1
>>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip



From wxt at rock-chips.com  Tue May 24 20:30:32 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 11:30:32 +0800
Subject: [PATCH v2 4/5] thermal: bang-bang governor: act on lower trip
 boundary
In-Reply-To: <a942e788aa285dcf88db38c6d03a36ce@mail.piie.net>
References: <20160524130610.GC8979@e104805>
 <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
 <1462268013-14992-5-git-send-email-wxt@rock-chips.com>
 <a942e788aa285dcf88db38c6d03a36ce@mail.piie.net>
Message-ID: <57451C58.6090808@rock-chips.com>


On 2016?05?25? 01:34, Peter Feuerer wrote:
> Hi,
>
> 24. Mai 2016 15:06 Uhr, "Javi Merino" <javi.merino at arm.com> schrieb:
>> Ccing Peter Feuerer, author of the bang bang governor.
>>
>> On Tue, May 03, 2016 at 05:33:32PM +0800, Caesar Wang wrote:
>>
>>> From: Sascha Hauer <s.hauer at pengutronix.de>
>>>
>>> With interrupt driven thermal zones we pass the lower and upper
>>> temperature on which shall be acted, so in the governor we have to act on
>>> the exact lower temperature to be consistent. Otherwise an interrupt maybe
>>> generated on the exact lower temperature, but the bang bang governor does
>>> not react since The polling driven zones have to be one step cooler before
>>> the governor reacts.
>>>
>>> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
>>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>>> Cc: Zhang Rui <rui.zhang at intel.com>
>>> Cc: Eduardo Valentin <edubezval at gmail.com>
>>> Cc: linux-pm at vger.kernel.org
> Acked-by: Peter Feuerer <peter at piie.net>

Okay, thanks your reviewing. :)

>
>
>>> ---
>>>
>>> Changes in v2:
>>> - Update the commit for patch[v2 4/5].
>>>
>>> drivers/thermal/gov_bang_bang.c | 2 +-
>>> 1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
>>> index 70836c5..9d1dfea 100644
>>> --- a/drivers/thermal/gov_bang_bang.c
>>> +++ b/drivers/thermal/gov_bang_bang.c
>>> @@ -59,7 +59,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
>>> if (instance->target == 0 && tz->temperature >= trip_temp)
>>> instance->target = 1;
>>> else if (instance->target == 1 &&
>>> - tz->temperature < trip_temp - trip_hyst)
>>> + tz->temperature <= trip_temp - trip_hyst)
>>> instance->target = 0;
>>>
>>> dev_dbg(&instance->cdev->device, "target=%d\n",
>>> --
>>> 1.9.1
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-pm" in
>>> the body of a message to majordomo at vger.kernel.org
>>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
>

-- 
caesar wang | software engineer | wxt at rock-chip.com




From wxt at rock-chips.com  Tue May 24 20:47:44 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 11:47:44 +0800
Subject: [PATCH v3 0/5] Thermal: Support for hardware-tracked trip points
Message-ID: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>

The history patches come from Mikko and Sascha.
    http://thread.gmane.org/gmane.linux.power-management.general/59451

Now, I pick them up to continue upstream.
Nevermind!

This series history patches:
v2: https://lkml.org/lkml/2016/5/3/220
v1: https://lkml.org/lkml/2016/4/24/227

This series adds support for hardware trip points. It picks up earlier
work from Mikko Perttunen. Mikko implemented hardware trip points as part
of the device tree support. It was suggested back then to move the
functionality to the thermal core instead of putting more code into the
device tree support. This series does exactly that.

This series patches rebase the conflicts.
Note that the hardware-tracked trip points are very well tested currently.

Verified and tested on https://github.com/Caesar-github/rockchip/tree/wip/fixes-thermal-0525
That's based on linux-kernel 20160524.


Changes in v3:
- as Javi comments on https://patchwork.kernel.org/patch/9001281/.
- add the lock for preventing the called from multi placce
- add the note for pre_low/high_trip.
- as the Javi comments on https://patchwork.kernel.org/patch/9001311/.
- add the select if they set the option for devicetree.
- Add the peter's ACK.

Changes in v2:
- update the sysfs-api.txt for set_trips.
- add the commit in patch[v2 2/5].
- Update the commit for patch[v2 4/5].

Caesar Wang (1):
  thermal: rockchip: add the set_trips function

Sascha Hauer (4):
  thermal: Add support for hardware-tracked trip points
  thermal: of: implement .set_trips for device tree thermal zones
  thermal: streamline get_trend callbacks
  thermal: bang-bang governor: act on lower trip boundary

 Documentation/thermal/sysfs-api.txt                |  7 +++
 drivers/thermal/gov_bang_bang.c                    |  2 +-
 drivers/thermal/of-thermal.c                       | 30 ++++++++-----
 drivers/thermal/rockchip_thermal.c                 | 39 ++++++++++++++++
 drivers/thermal/thermal_core.c                     | 52 ++++++++++++++++++++++
 drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 25 ++++-------
 include/linux/thermal.h                            | 13 +++++-
 7 files changed, 139 insertions(+), 29 deletions(-)

-- 
1.9.1



From wxt at rock-chips.com  Tue May 24 20:47:45 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 11:47:45 +0800
Subject: [PATCH v3 1/5] thermal: Add support for hardware-tracked trip points
In-Reply-To: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
References: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464148069-26254-2-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

This adds support for hardware-tracked trip points to the device tree
thermal sensor framework.

The framework supports an arbitrary number of trip points. Whenever
the current temperature is updated, the trip points immediately
below and above the current temperature are found. A .set_trips
callback is then called with the temperatures. If there is no trip
point above or below the current temperature, the passed trip
temperature will be -INT_MAX or INT_MAX respectively. In this callback,
the driver should program the hardware such that it is notified
when either of these trip points are triggered. When a trip point
is triggered, the driver should call `thermal_zone_device_update'
for the respective thermal zone. This will cause the trip points
to be updated again.

If .set_trips is not implemented, the framework behaves as before.

This patch is based on an earlier version from Mikko Perttunen
<mikko.perttunen at kapsi.fi>

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org

---

Changes in v3:
- as Javi comments on https://patchwork.kernel.org/patch/9001281/.
- add the lock for preventing the called from multi placce
- add the note for pre_low/high_trip.

Changes in v2:
- update the sysfs-api.txt for set_trips.

 Documentation/thermal/sysfs-api.txt |  7 +++++
 drivers/thermal/thermal_core.c      | 52 +++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h             |  7 +++++
 3 files changed, 66 insertions(+)

diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index efc3f3d..75d8838 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -49,6 +49,9 @@ temperature) and throttle appropriate devices.
 	.bind: bind the thermal zone device with a thermal cooling device.
 	.unbind: unbind the thermal zone device with a thermal cooling device.
 	.get_temp: get the current temperature of the thermal zone.
+	.set_trips: set the trip points window. Whenever the current temperature
+		    is updated, the trip points immediately below and above the
+		    current temperature are found.
 	.get_mode: get the current mode (enabled/disabled) of the thermal zone.
 	    - "enabled" means the kernel thermal management is enabled.
 	    - "disabled" will prevent kernel thermal driver action upon trip points
@@ -95,6 +98,10 @@ temperature) and throttle appropriate devices.
 			get_temp:	a pointer to a function that reads the
 					sensor temperature. This is mandatory
 					callback provided by sensor driver.
+			set_trips:      a pointer to a function that sets a
+					temperature window. When this window is
+					left the driver must inform the thermal
+					core via thermal_zone_device_update.
 			get_trend: 	a pointer to a function that reads the
 					sensor temperature trend.
 			set_emul_temp:	a pointer to a function that sets
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 5133cd1..e5bfbd3 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -520,6 +520,51 @@ exit:
 }
 EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
 
+static void thermal_zone_set_trips(struct thermal_zone_device *tz)
+{
+	int low = -INT_MAX;
+	int high = INT_MAX;
+	int trip_temp, hysteresis;
+	int temp = tz->temperature;
+	int i, ret;
+
+	if (!tz->ops->set_trips)
+		return;
+
+	for (i = 0; i < tz->trips; i++) {
+		int trip_low;
+
+		tz->ops->get_trip_temp(tz, i, &trip_temp);
+		tz->ops->get_trip_hyst(tz, i, &hysteresis);
+
+		trip_low = trip_temp - hysteresis;
+
+		if (trip_low < temp && trip_low > low)
+			low = trip_low;
+
+		if (trip_temp > temp && trip_temp < high)
+			high = trip_temp;
+	}
+
+	/* No need to change trip points */
+	if (tz->prev_low_trip == low && tz->prev_high_trip == high)
+		return;
+
+	tz->prev_low_trip = low;
+	tz->prev_high_trip = high;
+
+	dev_dbg(&tz->device, "new temperature boundaries: %d < x < %d\n",
+			low, high);
+
+	/*
+	 * Set a temperature window. When this window is left the driver
+	 * must inform the thermal core via thermal_zone_device_update.
+	 */
+	ret = tz->ops->set_trips(tz, low, high);
+	if (ret)
+		dev_err(&tz->device, "Failed to set trips: %d\n", ret);
+}
+
 static void update_temperature(struct thermal_zone_device *tz)
 {
 	int temp, ret;
@@ -569,6 +614,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
 
 	update_temperature(tz);
 
+	thermal_zone_set_trips(tz);
+
 	for (count = 0; count < tz->trips; count++)
 		handle_thermal_trip(tz, count);
 }
@@ -754,6 +801,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
 	 */
 	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
 
+	if (!ret)
+		thermal_zone_set_trips(tz);
+
 	return ret ? ret : count;
 }
 
@@ -1843,6 +1893,8 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
 	tz->trips = trips;
 	tz->passive_delay = passive_delay;
 	tz->polling_delay = polling_delay;
+	tz->prev_low_trip = INT_MAX;
+	tz->prev_high_trip = -INT_MAX;
 	/* A new thermal zone needs to be updated anyway. */
 	atomic_set(&tz->need_update, 1);
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index e45abe7..635c4003 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -98,6 +98,7 @@ struct thermal_zone_device_ops {
 	int (*unbind) (struct thermal_zone_device *,
 		       struct thermal_cooling_device *);
 	int (*get_temp) (struct thermal_zone_device *, int *);
+	int (*set_trips) (struct thermal_zone_device *, int, int);
 	int (*get_mode) (struct thermal_zone_device *,
 			 enum thermal_device_mode *);
 	int (*set_mode) (struct thermal_zone_device *,
@@ -168,6 +169,10 @@ struct thermal_attr {
  * @last_temperature:	previous temperature read
  * @emul_temperature:	emulated temperature when using CONFIG_THERMAL_EMULATION
  * @passive:		1 if you've crossed a passive trip point, 0 otherwise.
+ * @prev_low_trip:	the low current temperature if you've crossed a passive
+			trip point.
+ * @prev_high_trip:	the above current temperature if you've crossed a
+			passive trip point.
  * @forced_passive:	If > 0, temperature at which to switch on all ACPI
  *			processor cooling devices.  Currently only used by the
  *			step-wise governor.
@@ -199,6 +204,8 @@ struct thermal_zone_device {
 	int last_temperature;
 	int emul_temperature;
 	int passive;
+	int prev_low_trip;
+	int prev_high_trip;
 	unsigned int forced_passive;
 	atomic_t need_update;
 	struct thermal_zone_device_ops *ops;
-- 
1.9.1



From wxt at rock-chips.com  Tue May 24 20:47:46 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 11:47:46 +0800
Subject: [PATCH v3 2/5] thermal: of: implement .set_trips for device tree
 thermal zones
In-Reply-To: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
References: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464148069-26254-3-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

This patch implemnets .set_trips for device tree thermal zones.
As the hardware-tracked trip points is supported by thermal core patch[0].

patch[0]
"thermal: Add support for hardware-tracked trip points".

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>

---

Changes in v3:
- as the Javi comments on https://patchwork.kernel.org/patch/9001311/.
- add the select if they set the option for devicetree.

Changes in v2:
- add the commit in patch[v2 2/5].

 drivers/thermal/of-thermal.c | 19 +++++++++++++++++++
 include/linux/thermal.h      |  4 ++++
 2 files changed, 23 insertions(+)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index b8e509c..2d2a06f 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -101,6 +101,17 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
 	return data->ops->get_temp(data->sensor_data, temp);
 }
 
+static int of_thermal_set_trips(struct thermal_zone_device *tz,
+				int low, int high)
+{
+	struct __thermal_zone *data = tz->devdata;
+
+	if (!data->ops || !data->ops->set_trips)
+		return -EINVAL;
+
+	return data->ops->set_trips(data->sensor_data, low, high);
+}
+
 /**
  * of_thermal_get_ntrips - function to export number of available trip
  *			   points.
@@ -427,6 +438,14 @@ thermal_zone_of_add_sensor(struct device_node *zone,
 
 	tzd->ops->get_temp = of_thermal_get_temp;
 	tzd->ops->get_trend = of_thermal_get_trend;
+
+	/*
+	 * The thermal zone core will calculate the window if they have set the
+	 * optional set_trips pointer.
+	 */
+	if (ops->set_trips)
+		tzd->ops->set_trips = of_thermal_set_trips;
+
 	tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
 	mutex_unlock(&tzd->lock);
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 635c4003..f68da05 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -340,12 +340,16 @@ struct thermal_genl_event {
  *
  * Optional:
  * @get_trend: a pointer to a function that reads the sensor temperature trend.
+ * @set_trips: a pointer to a function that sets a temperature window. When
+ *	       this window is left the driver must inform the thermal core via
+ *	       thermal_zone_device_update.
  * @set_emul_temp: a pointer to a function that sets sensor emulated
  *		   temperature.
  */
 struct thermal_zone_of_device_ops {
 	int (*get_temp)(void *, int *);
 	int (*get_trend)(void *, long *);
+	int (*set_trips)(void *, int, int);
 	int (*set_emul_temp)(void *, int);
 	int (*set_trip_temp)(void *, int, int);
 };
-- 
1.9.1



From wxt at rock-chips.com  Tue May 24 20:47:47 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 11:47:47 +0800
Subject: [PATCH v3 3/5] thermal: streamline get_trend callbacks
In-Reply-To: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
References: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464148069-26254-4-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

The .get_trend callback in struct thermal_zone_device_ops has
the prototype:
        int (*get_trend) (struct thermal_zone_device *, int,
                          enum thermal_trend *);
whereas the .get_trend callback in struct thermal_zone_of_device_ops
has:
        int (*get_trend)(void *, long *);

Streamline both prototypes and add the trip argument to the OF callback
aswell and use enum thermal_trend * instead of an integer pointer.

While the OF prototype may be the better one, this should be decided at
framework level and not on OF level.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org
---

Changes in v3: None
Changes in v2: None

 drivers/thermal/of-thermal.c                       | 11 +---------
 drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 25 +++++++---------------
 include/linux/thermal.h                            |  2 +-
 3 files changed, 10 insertions(+), 28 deletions(-)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 2d2a06f..ba72c35 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -202,24 +202,15 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
 				enum thermal_trend *trend)
 {
 	struct __thermal_zone *data = tz->devdata;
-	long dev_trend;
 	int r;
 
 	if (!data->ops->get_trend)
 		return -EINVAL;
 
-	r = data->ops->get_trend(data->sensor_data, &dev_trend);
+	r = data->ops->get_trend(data->sensor_data, trip, trend);
 	if (r)
 		return r;
 
-	/* TODO: These intervals might have some thresholds, but in core code */
-	if (dev_trend > 0)
-		*trend = THERMAL_TREND_RAISING;
-	else if (dev_trend < 0)
-		*trend = THERMAL_TREND_DROPPING;
-	else
-		*trend = THERMAL_TREND_STABLE;
-
 	return 0;
 }
 
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
index 15c0a9a..4a6757c 100644
--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
@@ -239,7 +239,7 @@ static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int __ti_thermal_get_trend(void *p, long *trend)
+static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend)
 {
 	struct ti_thermal_data *data = p;
 	struct ti_bandgap *bgp;
@@ -252,22 +252,6 @@ static int __ti_thermal_get_trend(void *p, long *trend)
 	if (ret)
 		return ret;
 
-	*trend = tr;
-
-	return 0;
-}
-
-/* Get the temperature trend callback functions for thermal zone */
-static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
-				int trip, enum thermal_trend *trend)
-{
-	int ret;
-	long tr;
-
-	ret = __ti_thermal_get_trend(thermal->devdata, &tr);
-	if (ret)
-		return ret;
-
 	if (tr > 0)
 		*trend = THERMAL_TREND_RAISING;
 	else if (tr < 0)
@@ -278,6 +262,13 @@ static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
 	return 0;
 }
 
+/* Get the temperature trend callback functions for thermal zone */
+static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
+				int trip, enum thermal_trend *trend)
+{
+	return __ti_thermal_get_trend(thermal->devdata, trip, trend);
+}
+
 /* Get critical temperature callback functions for thermal zone */
 static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
 				    int *temp)
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index f68da05..669093c 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -348,7 +348,7 @@ struct thermal_genl_event {
  */
 struct thermal_zone_of_device_ops {
 	int (*get_temp)(void *, int *);
-	int (*get_trend)(void *, long *);
+	int (*get_trend)(void *, int, enum thermal_trend *);
 	int (*set_trips)(void *, int, int);
 	int (*set_emul_temp)(void *, int);
 	int (*set_trip_temp)(void *, int, int);
-- 
1.9.1



From wxt at rock-chips.com  Tue May 24 20:47:48 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 11:47:48 +0800
Subject: [PATCH v3 4/5] thermal: bang-bang governor: act on lower trip boundary
In-Reply-To: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
References: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464148069-26254-5-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

With interrupt driven thermal zones we pass the lower and upper
temperature on which shall be acted, so in the governor we have to act on
the exact lower temperature to be consistent. Otherwise an interrupt maybe
generated on the exact lower temperature, but the bang bang governor does
not react since The polling driven zones have to be one step cooler before
the governor reacts.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org
Acked-by: Peter Feuerer <peter at piie.net>

---

Changes in v3:
- Add the peter's ACK.

Changes in v2:
- Update the commit for patch[v2 4/5].

 drivers/thermal/gov_bang_bang.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
index 70836c5..9d1dfea 100644
--- a/drivers/thermal/gov_bang_bang.c
+++ b/drivers/thermal/gov_bang_bang.c
@@ -59,7 +59,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
 		if (instance->target == 0 && tz->temperature >= trip_temp)
 			instance->target = 1;
 		else if (instance->target == 1 &&
-				tz->temperature < trip_temp - trip_hyst)
+				tz->temperature <= trip_temp - trip_hyst)
 			instance->target = 0;
 
 		dev_dbg(&instance->cdev->device, "target=%d\n",
-- 
1.9.1



From wxt at rock-chips.com  Tue May 24 20:47:49 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 11:47:49 +0800
Subject: [PATCH v3 5/5] thermal: rockchip: add the set_trips function
In-Reply-To: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
References: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464148069-26254-6-git-send-email-wxt@rock-chips.com>

Whenever the current temperature is updated, the trip points immediately
below and above the current temperature are found. A sensor driver
callback `set_trips' is then called with the temperatures.
Lastly, The sensor will trigger the hardware high temperature interrupts
to increase the sampleing rate and throttle frequency to limit the
temperature rising When performing passive cooling.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org

---

Changes in v3: None
Changes in v2: None

 drivers/thermal/rockchip_thermal.c | 39 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index 86a1ab0..39e2eec 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -96,6 +96,7 @@ struct chip_tsadc_table {
  * @initialize: SoC special initialize tsadc controller method
  * @irq_ack: clear the interrupt
  * @get_temp: get the temperature
+ * @set_alarm_temp: set the high temperature interrupt
  * @set_tshut_temp: set the hardware-controlled shutdown temperature
  * @set_tshut_mode: set the hardware-controlled shutdown mode
  * @table: the chip-specific conversion table
@@ -119,6 +120,8 @@ struct rockchip_tsadc_chip {
 	/* Per-sensor methods */
 	int (*get_temp)(struct chip_tsadc_table table,
 			int chn, void __iomem *reg, int *temp);
+	void (*set_alarm_temp)(struct chip_tsadc_table table,
+			       int chn, void __iomem *reg, int temp);
 	void (*set_tshut_temp)(struct chip_tsadc_table table,
 			       int chn, void __iomem *reg, int temp);
 	void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
@@ -183,6 +186,7 @@ struct rockchip_thermal_data {
 #define TSADCV2_INT_EN				0x08
 #define TSADCV2_INT_PD				0x0c
 #define TSADCV2_DATA(chn)			(0x20 + (chn) * 0x04)
+#define TSADCV2_COMP_INT(chn)		        (0x30 + (chn) * 0x04)
 #define TSADCV2_COMP_SHUT(chn)		        (0x40 + (chn) * 0x04)
 #define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
 #define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
@@ -628,6 +632,20 @@ static int rk_tsadcv2_get_temp(struct chip_tsadc_table table,
 	return rk_tsadcv2_code_to_temp(table, val, temp);
 }
 
+static void rk_tsadcv2_alarm_temp(struct chip_tsadc_table table,
+				  int chn, void __iomem *regs, int temp)
+{
+	u32 alarm_value, int_en;
+
+	alarm_value = rk_tsadcv2_temp_to_code(table, temp);
+	writel_relaxed(alarm_value & table.data_mask,
+		       regs + TSADCV2_COMP_INT(chn));
+
+	int_en = readl_relaxed(regs + TSADCV2_INT_EN);
+	int_en |= TSADCV2_INT_SRC_EN(chn);
+	writel_relaxed(int_en, regs + TSADCV2_INT_EN);
+}
+
 static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table,
 				  int chn, void __iomem *regs, int temp)
 {
@@ -670,6 +688,7 @@ static const struct rockchip_tsadc_chip rk3228_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -694,6 +713,7 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
 	.irq_ack = rk_tsadcv2_irq_ack,
 	.control = rk_tsadcv2_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -718,6 +738,7 @@ static const struct rockchip_tsadc_chip rk3366_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -742,6 +763,7 @@ static const struct rockchip_tsadc_chip rk3368_tsadc_data = {
 	.irq_ack = rk_tsadcv2_irq_ack,
 	.control = rk_tsadcv2_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -766,6 +788,7 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -826,6 +849,21 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
+static int rockchip_thermal_set_trips(void *_sensor, int low, int high)
+{
+	struct rockchip_thermal_sensor *sensor = _sensor;
+	struct rockchip_thermal_data *thermal = sensor->thermal;
+	const struct rockchip_tsadc_chip *tsadc = thermal->chip;
+
+	dev_dbg(&thermal->pdev->dev, "%s: sensor %d: low: %d, high %d\n",
+		__func__, sensor->id, low, high);
+
+	tsadc->set_alarm_temp(tsadc->table,
+			      sensor->id, thermal->regs, high);
+
+	return 0;
+}
+
 static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
 {
 	struct rockchip_thermal_sensor *sensor = _sensor;
@@ -843,6 +881,7 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
 
 static const struct thermal_zone_of_device_ops rockchip_of_thermal_ops = {
 	.get_temp = rockchip_thermal_get_temp,
+	.set_trips = rockchip_thermal_set_trips,
 };
 
 static int rockchip_configure_from_dt(struct device *dev,
-- 
1.9.1



From wxt at rock-chips.com  Tue May 24 21:27:04 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 12:27:04 +0800
Subject: [PATCH] ARM64: dts: rockchip: add thermal zone node for rk3399 SoCs
Message-ID: <1464150424-27809-1-git-send-email-wxt@rock-chips.com>

This adds thermal zone node to rk3399 dtsi, rk3399 thermal data is
including the cpu and gpu sensor zone node.
At the moment, remove the rk3368 thermal data from rk399 dtsi.

The thermal zone node is the node containing all the required info
for describing a thermal zone, including its cooling device bindings.
The thermal zone node must contain, apart from its own properties, one
sub-node containing trip nodes and one sub-node containing all the zone
cooling maps.

The following is the parameter is introduced:
* polling-delay:
The maximum number of milliseconds to wait between polls

* polling-delay-passive:
The maximum number of milliseconds to wait between polls when performing
passive cooling.

* trips:
A sub-node which is a container of only trip point nodes required to
describe the thermal zone.

* cooling-maps:
A sub-node which is a container of only cooling device map nodes, used to
describe the relation between trips and cooling devices.

* cooling-device:
A phandle of a cooling device with its specifier, referring to which
cooling device is used in this cooling specifier binding. In the cooling
specifier, the first cell is the minimum cooling state and the second cell
is the maximum cooling state used in this map.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
---

 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 100 +++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a..cc4ca2a 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -45,6 +45,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
 	compatible = "rockchip,rk3399";
@@ -389,6 +390,95 @@
 		status = "disabled";
 	};
 
+	thermal-zones {
+		cpu-thermal: cpu {
+			polling-delay-passive = <100>; /* milliseconds */
+			polling-delay = <1000>; /* milliseconds */
+
+			thermal-sensors = <&tsadc 0>;
+
+			trips {
+				cpu_alert0: cpu_alert0 {
+					temperature = <70000>; /* millicelsius */
+					hysteresis = <2000>; /* millicelsius */
+					type = "passive";
+				};
+				cpu_alert1: cpu_alert1 {
+					temperature = <75000>; /* millicelsius */
+					hysteresis = <2000>; /* millicelsius */
+					type = "passive";
+				};
+				cpu_crit: cpu_crit {
+					temperature = <95000>; /* millicelsius */
+					hysteresis = <2000>; /* millicelsius */
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device =
+						<&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+				map1 {
+					trip = <&cpu_alert1>;
+					cooling-device =
+						<&cpu_l0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+
+		gpu-thermal: gpu {
+			polling-delay-passive = <100>; /* milliseconds */
+			polling-delay = <1000>; /* milliseconds */
+
+			thermal-sensors = <&tsadc 1>;
+
+			trips {
+				gpu_alert0: gpu_alert0 {
+					temperature = <75000>; /* millicelsius */
+					hysteresis = <2000>; /* millicelsius */
+					type = "passive";
+				};
+				gpu_crit: gpu_crit {
+					temperature = <95000>; /* millicelsius */
+					hysteresis = <2000>; /* millicelsius */
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&gpu_alert0>;
+					cooling-device =
+						<&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
+	tsadc: tsadc at ff260000 {
+		compatible = "rockchip,rk3399-tsadc";
+		reg = <0x0 0xff260000 0x0 0x100>;
+		interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+		rockchip,grf = <&grf>;
+		clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
+		clock-names = "tsadc", "apb_pclk";
+		assigned-clocks = <&cru SCLK_TSADC>;
+		assigned-clock-rates = <750000>;
+		resets = <&cru SRST_TSADC>;
+		reset-names = "tsadc-apb";
+		pinctrl-names = "init", "default", "sleep";
+		pinctrl-0 = <&otp_gpio>;
+		pinctrl-1 = <&otp_out>;
+		pinctrl-2 = <&otp_gpio>;
+		#thermal-sensor-cells = <1>;
+		rockchip,hw-tshut-temp = <95000>;
+		status = "disabled";
+	};
+
 	pmugrf: syscon at ff320000 {
 		compatible = "rockchip,rk3399-pmugrf", "syscon";
 		reg = <0x0 0xff320000 0x0 0x1000>;
@@ -881,6 +971,16 @@
 			};
 		};
 
+		tsadc {
+			otp_gpio: otp-gpio {
+				rockchip,pins = <1 6 RK_FUNC_GPIO &pcfg_pull_none>;
+			};
+
+			otp_out: otp-out {
+				rockchip,pins = <1 6 RK_FUNC_1 &pcfg_pull_none>;
+			};
+		};
+
 		uart0 {
 			uart0_xfer: uart0-xfer {
 				rockchip,pins =
-- 
1.9.1



From ykk at rock-chips.com  Tue May 24 22:54:30 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Wed, 25 May 2016 13:54:30 +0800
Subject: [PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
In-Reply-To: <8988677.GHLC4rSfsM@phil>
References: <1464066147-22734-1-git-send-email-ykk@rock-chips.com>
 <6183955.XzKjc41sjW@phil>
 <CAD=FV=WH6xYE6UiDxVK=cLnhoHnCvecSL4tk7FUVAnkGbQ-QOg@mail.gmail.com>
 <8988677.GHLC4rSfsM@phil>
Message-ID: <57453E16.4060805@rock-chips.com>


On 05/25/2016 02:23 AM, Heiko Stuebner wrote:
> Am Dienstag, 24. Mai 2016, 11:12:20 schrieb Doug Anderson:
>> Hi,
>>
>> On Tue, May 24, 2016 at 3:17 AM, Heiko Stuebner <heiko at sntech.de> wrote:
>>>> --- a/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
>>>> +++ b/Documentation/devicetree/bindings/display/bridge/analogix_dp.txt
>>>>
>>>> @@ -5,6 +5,7 @@ Required properties for dp-controller:
>>>>                platform specific such as:
>>>>                 * "samsung,exynos5-dp"
>>>>                 * "rockchip,rk3288-dp"
>>>>
>>>> +              * "rockchip,rk3399-edp"
>>> the cleanlines-freak in my likes to know if there is a difference
>>> between
>>> the rk3399 being called -edp here and -dp on the rk3288 :-)
>>>
>>> [...]
>> If I was a guessing man (which I'm not, but if I was), I'd guess that
>> this is because on rk3288 there was only one DP port and it was an EDP
>> port.  ...but since there was only one people just referred to it as
>> the "DP" port and that was codified in the bindings.  On rk3399 there
>> are two ports: one EDP and one DP.  All of a sudden we need to
>> differentiate.
>>
>> Any better suggestions for how to deal with that?
> nope - everything as it should be in that regard then - the rk3288-dp is
> permanent now anyway.
>
> But it looks like I'm sort of blind blind and only now have seen the
> separate DP controller chapter in the TRM (probably because I somehow didn't
> expect a second controller).
RK3399 eDP controller have cut off the DP-Audio function and DP-HDCP 
function, so it can't be treated as DP interfaces any more, that's why I 
call it "eDP".
>
>




From ykk at rock-chips.com  Tue May 24 22:55:11 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Wed, 25 May 2016 13:55:11 +0800
Subject: [PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
In-Reply-To: <6183955.XzKjc41sjW@phil>
References: <1464066147-22734-1-git-send-email-ykk@rock-chips.com>
 <1464073043-4931-1-git-send-email-ykk@rock-chips.com>
 <6183955.XzKjc41sjW@phil>
Message-ID: <57453E3F.8030600@rock-chips.com>



On 05/24/2016 06:17 PM, Heiko Stuebner wrote:
> Am Dienstag, 24. Mai 2016, 14:57:23 schrieb Yakir Yang:
> [........]
>> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c index 29c4105..d5d4e04
>> 100644
>> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
>> @@ -148,6 +148,10 @@ rockchip_dp_drm_encoder_atomic_check(struct
>> drm_encoder *encoder, struct drm_connector_state *conn_state)
>>   {
>>   	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
>> +	struct rockchip_dp_device *dp = to_dp(encoder);
>> +	int ret;
>> +
>> +	s->output_type = DRM_MODE_CONNECTOR_eDP;
>>
>>   	/*
>>   	 * FIXME(Yakir): driver should configure the CRTC output video
>> @@ -162,8 +166,27 @@ rockchip_dp_drm_encoder_atomic_check(struct
>> drm_encoder *encoder, * But if I configure CTRC to RGBaaa, and eDP driver
>> still keep * RGB666 input video mode, then screen would works prefect.
>>   	 */
>> -	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
>> -	s->output_type = DRM_MODE_CONNECTOR_eDP;
>> +
>> +	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
>> +	if (ret < 0)
>> +		return;
> this needs a value returned (probably ret), otherwise you create a
> warning: ?return? with no value, in function returning non-void
Done,

Thanks,
- Yakir
>
> drm_of_encoder_active_endpoint_id also always returns -EINVAL on rk3288-
> veyron-jerry because encoder->crtc is unset in
> drm_of_encoder_active_endpoint and that breaks display output right now.
>
> Looking through drm code it seems only two functions would set encoder->crtc
> - drm_atomic_helper_update_legacy_modeset_state
> - drm_crtc_helper_set_config
>
> drm_crtc_helper_set_config callback got dropped in the atomic-conversion and
> the other sounds to be somewhat in the legacy area.
>
> After that drm-internals get a bit confusing.
>
>
> Heiko
>
>
>




From wxt at rock-chips.com  Wed May 25 00:39:35 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 15:39:35 +0800
Subject: [RESEND PATCH] ARM64: dts: rockchip: add thermal zone node for rk3399
 SoCs
Message-ID: <1464161975-31299-1-git-send-email-wxt@rock-chips.com>

This adds thermal zone node to rk3399 dtsi, rk3399 thermal data is
including the cpu and gpu sensor zone node.

The thermal zone node is the node containing all the required info
for describing a thermal zone, including its cooling device bindings.
The thermal zone node must contain, apart from its own properties, one
sub-node containing trip nodes and one sub-node containing all the zone
cooling maps.

The following is the parameter is introduced:
* polling-delay:
The maximum number of milliseconds to wait between polls

* polling-delay-passive:
The maximum number of milliseconds to wait between polls when performing
passive cooling.

* trips:
A sub-node which is a container of only trip point nodes required to
describe the thermal zone.

* cooling-maps:
A sub-node which is a container of only cooling device map nodes, used to
describe the relation between trips and cooling devices.

* cooling-device:
A phandle of a cooling device with its specifier, referring to which
cooling device is used in this cooling specifier binding. In the cooling
specifier, the first cell is the minimum cooling state and the second cell
is the maximum cooling state used in this map.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
---

 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 100 +++++++++++++++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a..f8a80c2 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -45,6 +45,7 @@
 #include <dt-bindings/interrupt-controller/arm-gic.h>
 #include <dt-bindings/interrupt-controller/irq.h>
 #include <dt-bindings/pinctrl/rockchip.h>
+#include <dt-bindings/thermal/thermal.h>
 
 / {
 	compatible = "rockchip,rk3399";
@@ -389,6 +390,95 @@
 		status = "disabled";
 	};
 
+	thermal-zones {
+		cpu_thermal: cpu {
+			polling-delay-passive = <100>; /* milliseconds */
+			polling-delay = <1000>; /* milliseconds */
+
+			thermal-sensors = <&tsadc 0>;
+
+			trips {
+				cpu_alert0: cpu_alert0 {
+					temperature = <70000>; /* millicelsius */
+					hysteresis = <2000>; /* millicelsius */
+					type = "passive";
+				};
+				cpu_alert1: cpu_alert1 {
+					temperature = <75000>; /* millicelsius */
+					hysteresis = <2000>; /* millicelsius */
+					type = "passive";
+				};
+				cpu_crit: cpu_crit {
+					temperature = <95000>; /* millicelsius */
+					hysteresis = <2000>; /* millicelsius */
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&cpu_alert0>;
+					cooling-device =
+						<&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+				map1 {
+					trip = <&cpu_alert1>;
+					cooling-device =
+						<&cpu_l0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>,
+						<&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+
+		gpu_thermal: gpu {
+			polling-delay-passive = <100>; /* milliseconds */
+			polling-delay = <1000>; /* milliseconds */
+
+			thermal-sensors = <&tsadc 1>;
+
+			trips {
+				gpu_alert0: gpu_alert0 {
+					temperature = <75000>; /* millicelsius */
+					hysteresis = <2000>; /* millicelsius */
+					type = "passive";
+				};
+				gpu_crit: gpu_crit {
+					temperature = <95000>; /* millicelsius */
+					hysteresis = <2000>; /* millicelsius */
+					type = "critical";
+				};
+			};
+
+			cooling-maps {
+				map0 {
+					trip = <&gpu_alert0>;
+					cooling-device =
+						<&cpu_b0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
+		};
+	};
+
+	tsadc: tsadc at ff260000 {
+		compatible = "rockchip,rk3399-tsadc";
+		reg = <0x0 0xff260000 0x0 0x100>;
+		interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+		rockchip,grf = <&grf>;
+		clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
+		clock-names = "tsadc", "apb_pclk";
+		assigned-clocks = <&cru SCLK_TSADC>;
+		assigned-clock-rates = <750000>;
+		resets = <&cru SRST_TSADC>;
+		reset-names = "tsadc-apb";
+		pinctrl-names = "init", "default", "sleep";
+		pinctrl-0 = <&otp_gpio>;
+		pinctrl-1 = <&otp_out>;
+		pinctrl-2 = <&otp_gpio>;
+		#thermal-sensor-cells = <1>;
+		rockchip,hw-tshut-temp = <95000>;
+		status = "disabled";
+	};
+
 	pmugrf: syscon at ff320000 {
 		compatible = "rockchip,rk3399-pmugrf", "syscon";
 		reg = <0x0 0xff320000 0x0 0x1000>;
@@ -881,6 +971,16 @@
 			};
 		};
 
+		tsadc {
+			otp_gpio: otp-gpio {
+				rockchip,pins = <1 6 RK_FUNC_GPIO &pcfg_pull_none>;
+			};
+
+			otp_out: otp-out {
+				rockchip,pins = <1 6 RK_FUNC_1 &pcfg_pull_none>;
+			};
+		};
+
 		uart0 {
 			uart0_xfer: uart0-xfer {
 				rockchip,pins =
-- 
1.9.1



From william.wu at rock-chips.com  Wed May 25 00:55:45 2016
From: william.wu at rock-chips.com (William Wu)
Date: Wed, 25 May 2016 15:55:45 +0800
Subject: [PATCH v2 5/5] usb: dwc3: rockchip: add devicetree bindings
 documentation
In-Reply-To: <87a8jfu7h4.fsf@linux.intel.com>
References: <1463133155-20047-1-git-send-email-william.wu@rock-chips.com>
 <87a8jfu7h4.fsf@linux.intel.com>
Message-ID: <57455A81.5080101@rock-chips.com>

Hi Felipe,

On 05/24/2016 05:32 PM, Felipe Balbi wrote:
> Hi,
>
> William Wu <william.wu at rock-chips.com> writes:
>> This patch documents the device tree documentation required for
>> Rockchip USB3.0 core wrapper consist of USB3.0 IP from Synopsys.
>>
>> It could operate in device mode (SS, HS, FS) and host
>> mode (SS, HS, FS, LS).
>>
>> Signed-off-by: William Wu <william.wu at rock-chips.com>
>> ---
>> Changes in v2:
>> - add rockchip,dwc3.txt to Documentation/devicetree/bindings/ (Felipe, Brian)
>>
>>   .../devicetree/bindings/usb/rockchip,dwc3.txt      | 45 ++++++++++++++++++++++
>>   1 file changed, 45 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
>>
>> diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
>> new file mode 100644
>> index 0000000..10303d9
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
>> @@ -0,0 +1,45 @@
>> +Rockchip SuperSpeed DWC3 USB SoC controller
>> +
>> +Required properties:
>> +- compatible:	should contain "rockchip,dwc3"
>> +- clocks:		A list of phandle + clock-specifier pairs for the
>> +				clocks listed in clock-names
>> +- clock-names:	Should contain the following:
>> +  "clk_usb3otg0_ref"	Controller reference clk
>> +  "clk_usb3otg0_suspend"Controller suspend clk, can use 24 MHz or 32 KHz
>> +  "aclk_usb3"		Master/Core clock, have to be >= 62.5 MHz for SS operation
>> +
>> +
>> +Optional clocks:
>> +  "aclk_usb3otg0"	Aclk for specific usb controller clock.
>> +  "aclk_usb3_rksoc_axi_perf"  USB AXI perf clock.  Not present on all platforms.
>> +  "aclk_usb3_grf"	USB grf clock.  Not present on all platforms.
>> +
>> +Required child node:
>> +A child node must exist to represent the core DWC3 IP block. The name of
>> +the node is not important. The content of the node is defined in dwc3.txt.
>> +
>> +Phy documentation is provided in the following places:
>> +
>> +Example device nodes:
>> +
>> +	usbdrd3_0: usb at fe800000 {
>> +
> no reg property?
For now, we don't need reg property here. Because we only need to do
enable some clocks and populate its children in 
drivers/usb/dwc3/dwc3-of-simple.c.
And it's similar to arch/arm/boot/dts/exynos5420.dtsi usbdrd3_0 node.
> 		compatible = "rockchip,dwc3";
>> +		clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
>> +			 <&cru ACLK_USB3>, <&cru ACLK_USB3OTG0>,
>> +			 <&cru ACLK_USB3_RKSOC_AXI_PERF>, <&cru ACLK_USB3_GRF>;
>> +		clock-names = "clk_usb3otg0_ref", "clk_usb3otg0_suspend",
>> +			      "aclk_usb3", "aclk_usb3otg0",
>> +			      "aclk_usb3_rksoc_axi_perf", "aclk_usb3_grf";
>> +		#address-cells = <2>;
>> +		#size-cells = <2>;
>> +		ranges;
>> +		status = "disabled";
>> +		usbdrd_dwc3_0: dwc3 {
> no address here?
I think here don't  necessarily need address. The child node dwc3 can 
inherit address from the parent node.
And with this dtsi patch, the dev path show as follows:
/sys/devices/platform/usb at fe800000/fe800000.dwc3

Is it need for coding style or other reason?

>
>> +			compatible = "snps,dwc3";
>> +			reg = <0x0 0xfe800000 0x0 0x100000>;
>> +			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
>> +			dr_mode = "otg";
>> +			status = "disabled";
>> +		};
>> +	};
>> -- 
>> 1.9.1
>>
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html




From balbi at kernel.org  Wed May 25 01:04:12 2016
From: balbi at kernel.org (Felipe Balbi)
Date: Wed, 25 May 2016 11:04:12 +0300
Subject: [PATCH v2 5/5] usb: dwc3: rockchip: add devicetree bindings
 documentation
In-Reply-To: <57455A81.5080101@rock-chips.com>
References: <1463133155-20047-1-git-send-email-william.wu@rock-chips.com>
 <87a8jfu7h4.fsf@linux.intel.com> <57455A81.5080101@rock-chips.com>
Message-ID: <871t4qsgw3.fsf@linux.intel.com>


Hi,

William Wu <william.wu at rock-chips.com> writes:
> Hi Felipe,
>
> On 05/24/2016 05:32 PM, Felipe Balbi wrote:
>> Hi,
>>
>> William Wu <william.wu at rock-chips.com> writes:
>>> This patch documents the device tree documentation required for
>>> Rockchip USB3.0 core wrapper consist of USB3.0 IP from Synopsys.
>>>
>>> It could operate in device mode (SS, HS, FS) and host
>>> mode (SS, HS, FS, LS).
>>>
>>> Signed-off-by: William Wu <william.wu at rock-chips.com>
>>> ---
>>> Changes in v2:
>>> - add rockchip,dwc3.txt to Documentation/devicetree/bindings/ (Felipe, Brian)
>>>
>>>   .../devicetree/bindings/usb/rockchip,dwc3.txt      | 45 ++++++++++++++++++++++
>>>   1 file changed, 45 insertions(+)
>>>   create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
>>> new file mode 100644
>>> index 0000000..10303d9
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
>>> @@ -0,0 +1,45 @@
>>> +Rockchip SuperSpeed DWC3 USB SoC controller
>>> +
>>> +Required properties:
>>> +- compatible:	should contain "rockchip,dwc3"
>>> +- clocks:		A list of phandle + clock-specifier pairs for the
>>> +				clocks listed in clock-names
>>> +- clock-names:	Should contain the following:
>>> +  "clk_usb3otg0_ref"	Controller reference clk
>>> +  "clk_usb3otg0_suspend"Controller suspend clk, can use 24 MHz or 32 KHz
>>> +  "aclk_usb3"		Master/Core clock, have to be >= 62.5 MHz for SS operation
>>> +
>>> +
>>> +Optional clocks:
>>> +  "aclk_usb3otg0"	Aclk for specific usb controller clock.
>>> +  "aclk_usb3_rksoc_axi_perf"  USB AXI perf clock.  Not present on all platforms.
>>> +  "aclk_usb3_grf"	USB grf clock.  Not present on all platforms.
>>> +
>>> +Required child node:
>>> +A child node must exist to represent the core DWC3 IP block. The name of
>>> +the node is not important. The content of the node is defined in dwc3.txt.
>>> +
>>> +Phy documentation is provided in the following places:
>>> +
>>> +Example device nodes:
>>> +
>>> +	usbdrd3_0: usb at fe800000 {
>>> +
>> no reg property?
> For now, we don't need reg property here. Because we only need to do
> enable some clocks and populate its children in 
> drivers/usb/dwc3/dwc3-of-simple.c.
> And it's similar to arch/arm/boot/dts/exynos5420.dtsi usbdrd3_0 node.
>> 		compatible = "rockchip,dwc3";
>>> +		clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
>>> +			 <&cru ACLK_USB3>, <&cru ACLK_USB3OTG0>,
>>> +			 <&cru ACLK_USB3_RKSOC_AXI_PERF>, <&cru ACLK_USB3_GRF>;
>>> +		clock-names = "clk_usb3otg0_ref", "clk_usb3otg0_suspend",
>>> +			      "aclk_usb3", "aclk_usb3otg0",
>>> +			      "aclk_usb3_rksoc_axi_perf", "aclk_usb3_grf";
>>> +		#address-cells = <2>;
>>> +		#size-cells = <2>;
>>> +		ranges;
>>> +		status = "disabled";
>>> +		usbdrd_dwc3_0: dwc3 {
>> no address here?
> I think here don't  necessarily need address. The child node dwc3 can 
> inherit address from the parent node.
> And with this dtsi patch, the dev path show as follows:
> /sys/devices/platform/usb at fe800000/fe800000.dwc3
>
> Is it need for coding style or other reason?

I don't think your arguments match what devicetree folks want to see in
DT. Let's ask them. Rob, care to look at this one?

>
>>
>>> +			compatible = "snps,dwc3";
>>> +			reg = <0x0 0xfe800000 0x0 0x100000>;
>>> +			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
>>> +			dr_mode = "otg";
>>> +			status = "disabled";
>>> +		};
>>> +	};
>>> -- 
>>> 1.9.1
>>>
>>>
>>> --
>>> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
>>> the body of a message to majordomo at vger.kernel.org
>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
> the body of a message to majordomo at vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 818 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160525/c182e34a/attachment.sig>

From zhengxing at rock-chips.com  Wed May 25 01:51:56 2016
From: zhengxing at rock-chips.com (Xing Zheng)
Date: Wed, 25 May 2016 16:51:56 +0800
Subject: [PATCH] clk: rockchip: add a dummy clock for the watchdog pclk on
 rk3399
Message-ID: <1464166316-22480-1-git-send-email-zhengxing@rock-chips.com>

Like rk3288, the pclk supplying the watchdog is controlled via the
SGRF register area. Additionally the SGRF isn't even writable in
every boot mode.

But still the clock control is available and in the future someone
might want to use it. Therefore define a simple clock for the time
being so that the watchdog driver can read its rate.

Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
---

 drivers/clk/rockchip/clk-rk3399.c |    9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
index 291543f..b6742fa 100644
--- a/drivers/clk/rockchip/clk-rk3399.c
+++ b/drivers/clk/rockchip/clk-rk3399.c
@@ -1498,6 +1498,7 @@ static void __init rk3399_clk_init(struct device_node *np)
 {
 	struct rockchip_clk_provider *ctx;
 	void __iomem *reg_base;
+	struct clk *clk;
 
 	reg_base = of_iomap(np, 0);
 	if (!reg_base) {
@@ -1511,6 +1512,14 @@ static void __init rk3399_clk_init(struct device_node *np)
 		return;
 	}
 
+	/* Watchdog pclk is controlled by RK3399 SECURE_GRF_SOC_CON3[8]. */
+	clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_alive", 0, 1, 1);
+	if (IS_ERR(clk))
+		pr_warn("%s: could not register clock pclk_wdt: %ld\n",
+			__func__, PTR_ERR(clk));
+	else
+		rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
+
 	rockchip_clk_register_plls(ctx, rk3399_pll_clks,
 				   ARRAY_SIZE(rk3399_pll_clks), -1);
 
-- 
1.7.9.5




From william.wu at rock-chips.com  Wed May 25 01:58:38 2016
From: william.wu at rock-chips.com (William Wu)
Date: Wed, 25 May 2016 16:58:38 +0800
Subject: [PATCH v2 5/5] usb: dwc3: rockchip: add devicetree bindings
 documentation
In-Reply-To: <871t4qsgw3.fsf@linux.intel.com>
References: <1463133155-20047-1-git-send-email-william.wu@rock-chips.com>
 <87a8jfu7h4.fsf@linux.intel.com> <57455A81.5080101@rock-chips.com>
 <871t4qsgw3.fsf@linux.intel.com>
Message-ID: <5745693E.9000309@rock-chips.com>

Hi Felipe & Rob,
On 05/25/2016 04:04 PM, Felipe Balbi wrote:
> Hi,
>
> William Wu <william.wu at rock-chips.com> writes:
>> Hi Felipe,
>>
>> On 05/24/2016 05:32 PM, Felipe Balbi wrote:
>>> Hi,
>>>
>>> William Wu <william.wu at rock-chips.com> writes:
>>>> This patch documents the device tree documentation required for
>>>> Rockchip USB3.0 core wrapper consist of USB3.0 IP from Synopsys.
>>>>
>>>> It could operate in device mode (SS, HS, FS) and host
>>>> mode (SS, HS, FS, LS).
>>>>
>>>> Signed-off-by: William Wu <william.wu at rock-chips.com>
>>>> ---
>>>> Changes in v2:
>>>> - add rockchip,dwc3.txt to Documentation/devicetree/bindings/ (Felipe, Brian)
>>>>
>>>>    .../devicetree/bindings/usb/rockchip,dwc3.txt      | 45 ++++++++++++++++++++++
>>>>    1 file changed, 45 insertions(+)
>>>>    create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
>>>> new file mode 100644
>>>> index 0000000..10303d9
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
>>>> @@ -0,0 +1,45 @@
>>>> +Rockchip SuperSpeed DWC3 USB SoC controller
>>>> +
>>>> +Required properties:
>>>> +- compatible:	should contain "rockchip,dwc3"
>>>> +- clocks:		A list of phandle + clock-specifier pairs for the
>>>> +				clocks listed in clock-names
>>>> +- clock-names:	Should contain the following:
>>>> +  "clk_usb3otg0_ref"	Controller reference clk
>>>> +  "clk_usb3otg0_suspend"Controller suspend clk, can use 24 MHz or 32 KHz
>>>> +  "aclk_usb3"		Master/Core clock, have to be >= 62.5 MHz for SS operation
>>>> +
>>>> +
>>>> +Optional clocks:
>>>> +  "aclk_usb3otg0"	Aclk for specific usb controller clock.
>>>> +  "aclk_usb3_rksoc_axi_perf"  USB AXI perf clock.  Not present on all platforms.
>>>> +  "aclk_usb3_grf"	USB grf clock.  Not present on all platforms.
>>>> +
>>>> +Required child node:
>>>> +A child node must exist to represent the core DWC3 IP block. The name of
>>>> +the node is not important. The content of the node is defined in dwc3.txt.
>>>> +
>>>> +Phy documentation is provided in the following places:
>>>> +
>>>> +Example device nodes:
>>>> +
>>>> +	usbdrd3_0: usb at fe800000 {
>>>> +
>>> no reg property?
>> For now, we don't need reg property here. Because we only need to do
>> enable some clocks and populate its children in
>> drivers/usb/dwc3/dwc3-of-simple.c.
>> And it's similar to arch/arm/boot/dts/exynos5420.dtsi usbdrd3_0 node.
>>> 		compatible = "rockchip,dwc3";
>>>> +		clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
>>>> +			 <&cru ACLK_USB3>, <&cru ACLK_USB3OTG0>,
>>>> +			 <&cru ACLK_USB3_RKSOC_AXI_PERF>, <&cru ACLK_USB3_GRF>;
>>>> +		clock-names = "clk_usb3otg0_ref", "clk_usb3otg0_suspend",
>>>> +			      "aclk_usb3", "aclk_usb3otg0",
>>>> +			      "aclk_usb3_rksoc_axi_perf", "aclk_usb3_grf";
>>>> +		#address-cells = <2>;
>>>> +		#size-cells = <2>;
>>>> +		ranges;
>>>> +		status = "disabled";
>>>> +		usbdrd_dwc3_0: dwc3 {
>>> no address here?
>> I think here don't  necessarily need address. The child node dwc3 can
>> inherit address from the parent node.
>> And with this dtsi patch, the dev path show as follows:
>> /sys/devices/platform/usb at fe800000/fe800000.dwc3
>>
>> Is it need for coding style or other reason?
> I don't think your arguments match what devicetree folks want to see in
> DT. Let's ask them. Rob, care to look at this one?
Sorry, I need to correct myself. I have done some test, and the result 
shows that
the  child node dwc3 don't inherit address from the parent node, but get 
address
from its reg property. And It seems that whether I add address here or 
not, the
dwc3 node always get address from reg property.
However, I don't know much about the DT. But I think it's better to add 
address here than no.
>
>>>> +			compatible = "snps,dwc3";
>>>> +			reg = <0x0 0xfe800000 0x0 0x100000>;
>>>> +			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
>>>> +			dr_mode = "otg";
>>>> +			status = "disabled";
>>>> +		};
>>>> +	};
>>>> -- 
>>>> 1.9.1
>>>>
>>>>
>>>> --
>>>> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
>>>> the body of a message to majordomo at vger.kernel.org
>>>> More majordomo info at  http://vger.kernel.org/majordomo-info.html
>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-usb" in
>> the body of a message to majordomo at vger.kernel.org
>> More majordomo info at  http://vger.kernel.org/majordomo-info.html




From wxt at rock-chips.com  Wed May 25 02:49:58 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 17:49:58 +0800
Subject: [PATCH 1/5] dt-bindings: document rk3399 rk-timer bindings
In-Reply-To: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464169802-6033-2-git-send-email-wxt@rock-chips.com>

From: Huang Tao <huangtao at rock-chips.com>

Add compatible string for rk3399 because which timer is a little
different from older SoCs. So rename the file name from
rockchip,rk3288-timer.txt to rockchip,rk-timer.txt.
Clarify rockchip,rk3288-timer supported SoCs.

Signed-off-by: Huang Tao <huangtao at rock-chips.com>
Cc: Rob Herring <robh+dt at kernel.org>
Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Heiko Stuebner <heiko at sntech.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
---

 .../timer/{rockchip,rk3288-timer.txt => rockchip,rk-timer.txt}      | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)
 rename Documentation/devicetree/bindings/timer/{rockchip,rk3288-timer.txt => rockchip,rk-timer.txt} (75%)

diff --git a/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.txt
similarity index 75%
rename from Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt
rename to Documentation/devicetree/bindings/timer/rockchip,rk-timer.txt
index 87f0b00..a41b184 100644
--- a/Documentation/devicetree/bindings/timer/rockchip,rk3288-timer.txt
+++ b/Documentation/devicetree/bindings/timer/rockchip,rk-timer.txt
@@ -1,7 +1,9 @@
-Rockchip rk3288 timer
+Rockchip rk timer
 
 Required properties:
-- compatible: shall be "rockchip,rk3288-timer"
+- compatible: shall be one of:
+  "rockchip,rk3288-timer" - for rk3066, rk3036, rk3188, rk322x, rk3288, rk3368
+  "rockchip,rk3399-timer" - for rk3399
 - reg: base address of the timer register starting with TIMERS CONTROL register
 - interrupts: should contain the interrupts for Timer0
 - clocks : must contain an entry for each entry in clock-names
-- 
1.9.1



From wxt at rock-chips.com  Wed May 25 02:49:57 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 17:49:57 +0800
Subject: [PATCH 0/5] clocksource: rockchip/timer: Support rktimer for rk3399
Message-ID: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>

This series patches had been tested on rockchip inside kernel.
In order to support the rk3399 SoC timer and turn off interrupts and IPIs to
save power in idle.
Okay, it still works bootup on rk3288/other SoCs, even though many socs hasn't used
the broadcast timer.

Easy to test for my borad.
localhost / # cat /proc/interrupts
CPU0       CPU1       CPU2       CPU3       CPU4       CPU5
1:          0          0          0          0          0          0     GICv3  29 Edge      arch_timer
...
5:          0          0          0          0          0          0     GICv3 113 Level     rk_timer
..

localhost / # cat /proc/timer_list | grep event_handler
get "event_handler:  hrtimer_interrupt"
event_handler:  tick_handle_oneshot_broadcast
event_handler:  hrtimer_interrupt

That should work for my board.



Huang Tao (5):
  dt-bindings: document rk3399 rk-timer bindings
  clocksource: rockchip: remove unnecessary clear irq before request_irq
  clocksource: rockchip: add dynamic irq flag to the timer
  clocksource: rockchip: add support for rk3399 SoC
  ARM64: dts: rockchip: add rktimer device node for rk3399

 ...chip,rk3288-timer.txt => rockchip,rk-timer.txt} |   6 +-
 arch/arm64/boot/dts/rockchip/rk3399.dtsi           |   8 ++
 drivers/clocksource/rockchip_timer.c               | 120 ++++++++++++++++-----
 3 files changed, 106 insertions(+), 28 deletions(-)
 rename Documentation/devicetree/bindings/timer/{rockchip,rk3288-timer.txt => rockchip,rk-timer.txt} (75%)

-- 
1.9.1



From wxt at rock-chips.com  Wed May 25 02:49:59 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 17:49:59 +0800
Subject: [PATCH 2/5] clocksource: rockchip: remove unnecessary clear irq
 before request_irq
In-Reply-To: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464169802-6033-3-git-send-email-wxt@rock-chips.com>

From: Huang Tao <huangtao at rock-chips.com>

rk_timer_interrupt_clear and rk_timer_disable is unnecessary before
request_irq. Timer should keep disabled before booting Linux.

Signed-off-by: Huang Tao <huangtao at rock-chips.com>
Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Heiko Stuebner <heiko at sntech.de>
Tested-by: Jianqun Xu <jay.xu at rock-chips.com>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
---

 drivers/clocksource/rockchip_timer.c | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index b991b28..b93fed6 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -158,9 +158,6 @@ static void __init rk_timer_init(struct device_node *np)
 	ce->cpumask = cpumask_of(0);
 	ce->rating = 250;
 
-	rk_timer_interrupt_clear(ce);
-	rk_timer_disable(ce);
-
 	ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
 	if (ret) {
 		pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
-- 
1.9.1



From wxt at rock-chips.com  Wed May 25 02:50:00 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 17:50:00 +0800
Subject: [PATCH 3/5] clocksource: rockchip: add dynamic irq flag to the timer
In-Reply-To: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464169802-6033-4-git-send-email-wxt@rock-chips.com>

From: Huang Tao <huangtao at rock-chips.com>

The rockchip timer is broadcast timer. Add CLOCK_EVT_FEAT_DYNIRQ
flag and set cpumask to all cpu to save power by avoid unnecessary
wakeups and IPIs.

Signed-off-by: Huang Tao <huangtao at rock-chips.com>
Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Heiko Stuebner <heiko at sntech.de>
Tested-by: Jianqun Xu <jay.xu at rock-chips.com>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
---

 drivers/clocksource/rockchip_timer.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index b93fed6..f3dfb1a 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -150,12 +150,13 @@ static void __init rk_timer_init(struct device_node *np)
 	}
 
 	ce->name = TIMER_NAME;
-	ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
+	ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
+		       CLOCK_EVT_FEAT_DYNIRQ;
 	ce->set_next_event = rk_timer_set_next_event;
 	ce->set_state_shutdown = rk_timer_shutdown;
 	ce->set_state_periodic = rk_timer_set_periodic;
 	ce->irq = irq;
-	ce->cpumask = cpumask_of(0);
+	ce->cpumask = cpu_all_mask;
 	ce->rating = 250;
 
 	ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
-- 
1.9.1



From wxt at rock-chips.com  Wed May 25 02:50:01 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 17:50:01 +0800
Subject: [PATCH 4/5] clocksource: rockchip: add support for rk3399 SoC
In-Reply-To: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464169802-6033-5-git-send-email-wxt@rock-chips.com>

From: Huang Tao <huangtao at rock-chips.com>

The CONTROL register offset is different from old SoCs.
For Linux driver, there are not functional changes at all.
Let's call it v2.

Signed-off-by: Huang Tao <huangtao at rock-chips.com>
Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Heiko Stuebner <heiko at sntech.de>
Tested-by: Jianqun Xu <jay.xu at rock-chips.com>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
---

 drivers/clocksource/rockchip_timer.c | 112 ++++++++++++++++++++++++++++-------
 1 file changed, 91 insertions(+), 21 deletions(-)

diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
index f3dfb1a..7ce1d08 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -19,8 +19,9 @@
 
 #define TIMER_LOAD_COUNT0	0x00
 #define TIMER_LOAD_COUNT1	0x04
-#define TIMER_CONTROL_REG	0x10
+#define TIMER_V1_CONTROL_REG	0x10
 #define TIMER_INT_STATUS	0x18
+#define TIMER_V2_CONTROL_REG	0x1c
 
 #define TIMER_DISABLE		0x0
 #define TIMER_ENABLE		0x1
@@ -46,15 +47,26 @@ static inline void __iomem *rk_base(struct clock_event_device *ce)
 	return rk_timer(ce)->base;
 }
 
-static inline void rk_timer_disable(struct clock_event_device *ce)
+static inline void rk_timer_v1_disable(struct clock_event_device *ce)
 {
-	writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
+	writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_V1_CONTROL_REG);
 }
 
-static inline void rk_timer_enable(struct clock_event_device *ce, u32 flags)
+static inline void rk_timer_v1_enable(struct clock_event_device *ce, u32 flags)
 {
 	writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
-		       rk_base(ce) + TIMER_CONTROL_REG);
+		       rk_base(ce) + TIMER_V1_CONTROL_REG);
+}
+
+static inline void rk_timer_v2_disable(struct clock_event_device *ce)
+{
+	writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_V2_CONTROL_REG);
+}
+
+static inline void rk_timer_v2_enable(struct clock_event_device *ce, u32 flags)
+{
+	writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
+		       rk_base(ce) + TIMER_V2_CONTROL_REG);
 }
 
 static void rk_timer_update_counter(unsigned long cycles,
@@ -69,44 +81,82 @@ static void rk_timer_interrupt_clear(struct clock_event_device *ce)
 	writel_relaxed(1, rk_base(ce) + TIMER_INT_STATUS);
 }
 
-static inline int rk_timer_set_next_event(unsigned long cycles,
-					  struct clock_event_device *ce)
+static int rk_timer_v1_set_next_event(unsigned long cycles,
+				      struct clock_event_device *ce)
 {
-	rk_timer_disable(ce);
+	rk_timer_v1_disable(ce);
 	rk_timer_update_counter(cycles, ce);
-	rk_timer_enable(ce, TIMER_MODE_USER_DEFINED_COUNT);
+	rk_timer_v1_enable(ce, TIMER_MODE_USER_DEFINED_COUNT);
 	return 0;
 }
 
-static int rk_timer_shutdown(struct clock_event_device *ce)
+static int rk_timer_v1_shutdown(struct clock_event_device *ce)
 {
-	rk_timer_disable(ce);
+	rk_timer_v1_disable(ce);
 	return 0;
 }
 
-static int rk_timer_set_periodic(struct clock_event_device *ce)
+static int rk_timer_v1_set_periodic(struct clock_event_device *ce)
 {
-	rk_timer_disable(ce);
+	rk_timer_v1_disable(ce);
 	rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce);
-	rk_timer_enable(ce, TIMER_MODE_FREE_RUNNING);
+	rk_timer_v1_enable(ce, TIMER_MODE_FREE_RUNNING);
 	return 0;
 }
 
-static irqreturn_t rk_timer_interrupt(int irq, void *dev_id)
+static irqreturn_t rk_timer_v1_interrupt(int irq, void *dev_id)
 {
 	struct clock_event_device *ce = dev_id;
 
 	rk_timer_interrupt_clear(ce);
 
 	if (clockevent_state_oneshot(ce))
-		rk_timer_disable(ce);
+		rk_timer_v1_disable(ce);
 
 	ce->event_handler(ce);
 
 	return IRQ_HANDLED;
 }
 
-static void __init rk_timer_init(struct device_node *np)
+static int rk_timer_v2_set_next_event(unsigned long cycles,
+				      struct clock_event_device *ce)
+{
+	rk_timer_v2_disable(ce);
+	rk_timer_update_counter(cycles, ce);
+	rk_timer_v2_enable(ce, TIMER_MODE_USER_DEFINED_COUNT);
+	return 0;
+}
+
+static int rk_timer_v2_shutdown(struct clock_event_device *ce)
+{
+	rk_timer_v2_disable(ce);
+	return 0;
+}
+
+static int rk_timer_v2_set_periodic(struct clock_event_device *ce)
+{
+	rk_timer_v2_disable(ce);
+	rk_timer_update_counter(rk_timer(ce)->freq / HZ - 1, ce);
+	rk_timer_v2_enable(ce, TIMER_MODE_FREE_RUNNING);
+	return 0;
+}
+
+static irqreturn_t rk_timer_v2_interrupt(int irq, void *dev_id)
+{
+	struct clock_event_device *ce = dev_id;
+
+	rk_timer_interrupt_clear(ce);
+
+	if (clockevent_state_oneshot(ce))
+		rk_timer_v2_disable(ce);
+
+	ce->event_handler(ce);
+
+	return IRQ_HANDLED;
+}
+
+static void __init rk_timer_init(struct device_node *np,
+				 irq_handler_t rk_timer_interrupt)
 {
 	struct clock_event_device *ce = &bc_timer.ce;
 	struct clk *timer_clk;
@@ -152,9 +202,6 @@ static void __init rk_timer_init(struct device_node *np)
 	ce->name = TIMER_NAME;
 	ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
 		       CLOCK_EVT_FEAT_DYNIRQ;
-	ce->set_next_event = rk_timer_set_next_event;
-	ce->set_state_shutdown = rk_timer_shutdown;
-	ce->set_state_periodic = rk_timer_set_periodic;
 	ce->irq = irq;
 	ce->cpumask = cpu_all_mask;
 	ce->rating = 250;
@@ -177,4 +224,27 @@ out_unmap:
 	iounmap(bc_timer.base);
 }
 
-CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
+static void __init rk_timer_v1_init(struct device_node *np)
+{
+	struct clock_event_device *ce = &bc_timer.ce;
+
+	ce->set_next_event = rk_timer_v1_set_next_event;
+	ce->set_state_shutdown = rk_timer_v1_shutdown;
+	ce->set_state_periodic = rk_timer_v1_set_periodic;
+
+	rk_timer_init(np, rk_timer_v1_interrupt);
+}
+
+static void __init rk_timer_v2_init(struct device_node *np)
+{
+	struct clock_event_device *ce = &bc_timer.ce;
+
+	ce->set_next_event = rk_timer_v2_set_next_event;
+	ce->set_state_shutdown = rk_timer_v2_shutdown;
+	ce->set_state_periodic = rk_timer_v2_set_periodic;
+
+	rk_timer_init(np, rk_timer_v2_interrupt);
+}
+
+CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer", rk_timer_v1_init);
+CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer", rk_timer_v2_init);
-- 
1.9.1



From wxt at rock-chips.com  Wed May 25 02:50:02 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Wed, 25 May 2016 17:50:02 +0800
Subject: [PATCH 5/5] ARM64: dts: rockchip: add rktimer device node for rk3399
In-Reply-To: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464169802-6033-6-git-send-email-wxt@rock-chips.com>

From: Huang Tao <huangtao at rock-chips.com>

Select rktimer0 as broadcast timer.

Signed-off-by: Huang Tao <huangtao at rock-chips.com>
Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: Heiko Stuebner <heiko at sntech.de>
Tested-by: Jianqun Xu <jay.xu at rock-chips.com>

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
---

 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a..f0c0d76 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -492,6 +492,14 @@
 		interrupts = <GIC_SPI 120 IRQ_TYPE_LEVEL_HIGH>;
 	};
 
+	rktimer: rktimer at ff850000 {
+		compatible = "rockchip,rk3399-timer";
+		reg = <0x0 0xff850000 0x0 0x1000>;
+		interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru PCLK_TIMER0>, <&cru SCLK_TIMER00>;
+		clock-names = "pclk", "timer";
+	};
+
 	spdif: spdif at ff870000 {
 		compatible = "rockchip,rk3399-spdif";
 		reg = <0x0 0xff870000 0x0 0x1000>;
-- 
1.9.1



From javi.merino at arm.com  Wed May 25 09:42:58 2016
From: javi.merino at arm.com (Javi Merino)
Date: Wed, 25 May 2016 17:42:58 +0100
Subject: [PATCH v3 1/5] thermal: Add support for hardware-tracked trip
 points
In-Reply-To: <1464148069-26254-2-git-send-email-wxt@rock-chips.com>
References: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
 <1464148069-26254-2-git-send-email-wxt@rock-chips.com>
Message-ID: <20160525164258.GA11807@e104805>

Hi Caesar,

On Wed, May 25, 2016 at 11:47:45AM +0800, Caesar Wang wrote:
> From: Sascha Hauer <s.hauer at pengutronix.de>
> 
> This adds support for hardware-tracked trip points to the device tree
> thermal sensor framework.
> 
> The framework supports an arbitrary number of trip points. Whenever
> the current temperature is updated, the trip points immediately
> below and above the current temperature are found. A .set_trips
> callback is then called with the temperatures. If there is no trip
> point above or below the current temperature, the passed trip
> temperature will be -INT_MAX or INT_MAX respectively. In this callback,
> the driver should program the hardware such that it is notified
> when either of these trip points are triggered. When a trip point
> is triggered, the driver should call `thermal_zone_device_update'
> for the respective thermal zone. This will cause the trip points
> to be updated again.
> 
> If .set_trips is not implemented, the framework behaves as before.
> 
> This patch is based on an earlier version from Mikko Perttunen
> <mikko.perttunen at kapsi.fi>
> 
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Zhang Rui <rui.zhang at intel.com>
> Cc: Eduardo Valentin <edubezval at gmail.com>
> Cc: linux-pm at vger.kernel.org
> 
> ---
> 
> Changes in v3:
> - as Javi comments on https://patchwork.kernel.org/patch/9001281/.
> - add the lock for preventing the called from multi placce
> - add the note for pre_low/high_trip.
> 
> Changes in v2:
> - update the sysfs-api.txt for set_trips.
> 
>  Documentation/thermal/sysfs-api.txt |  7 +++++
>  drivers/thermal/thermal_core.c      | 52 +++++++++++++++++++++++++++++++++++++
>  include/linux/thermal.h             |  7 +++++
>  3 files changed, 66 insertions(+)
> 
> diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
> index efc3f3d..75d8838 100644
> --- a/Documentation/thermal/sysfs-api.txt
> +++ b/Documentation/thermal/sysfs-api.txt
> @@ -49,6 +49,9 @@ temperature) and throttle appropriate devices.
>  	.bind: bind the thermal zone device with a thermal cooling device.
>  	.unbind: unbind the thermal zone device with a thermal cooling device.
>  	.get_temp: get the current temperature of the thermal zone.
> +	.set_trips: set the trip points window. Whenever the current temperature
> +		    is updated, the trip points immediately below and above the
> +		    current temperature are found.
>  	.get_mode: get the current mode (enabled/disabled) of the thermal zone.
>  	    - "enabled" means the kernel thermal management is enabled.
>  	    - "disabled" will prevent kernel thermal driver action upon trip points
> @@ -95,6 +98,10 @@ temperature) and throttle appropriate devices.
>  			get_temp:	a pointer to a function that reads the
>  					sensor temperature. This is mandatory
>  					callback provided by sensor driver.
> +			set_trips:      a pointer to a function that sets a
> +					temperature window. When this window is
> +					left the driver must inform the thermal
> +					core via thermal_zone_device_update.
>  			get_trend: 	a pointer to a function that reads the
>  					sensor temperature trend.
>  			set_emul_temp:	a pointer to a function that sets
> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
> index 5133cd1..e5bfbd3 100644
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -520,6 +520,51 @@ exit:
>  }
>  EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
>  
> +static void thermal_zone_set_trips(struct thermal_zone_device *tz)
> +{
> +	int low = -INT_MAX;
> +	int high = INT_MAX;
> +	int trip_temp, hysteresis;
> +	int temp = tz->temperature;
> +	int i, ret;
> +
> +	if (!tz->ops->set_trips)
> +		return;
> +
> +	for (i = 0; i < tz->trips; i++) {
> +		int trip_low;
> +
> +		tz->ops->get_trip_temp(tz, i, &trip_temp);
> +		tz->ops->get_trip_hyst(tz, i, &hysteresis);
> +
> +		trip_low = trip_temp - hysteresis;
> +
> +		if (trip_low < temp && trip_low > low)
> +			low = trip_low;
> +
> +		if (trip_temp > temp && trip_temp < high)
> +			high = trip_temp;
> +	}
> +
> +	/* No need to change trip points */
> +	if (tz->prev_low_trip == low && tz->prev_high_trip == high)
> +		return;
> +
> +	tz->prev_low_trip = low;
> +	tz->prev_high_trip = high;
> +
> +	dev_dbg(&tz->device, "new temperature boundaries: %d < x < %d\n",
> +			low, high);
> +
> +	/*
> +	 * Set a temperature window. When this window is left the driver
> +	 * must inform the thermal core via thermal_zone_device_update.
> +	 */
> +	ret = tz->ops->set_trips(tz, low, high);
> +	if (ret)
> +		dev_err(&tz->device, "Failed to set trips: %d\n", ret);

In the v2 review
(http://article.gmane.org/gmane.linux.documentation/38442) you agreed
to add locking but you haven't done it.  Maybe you sent the wrong
version?

Cheers,
Javi


From javi.merino at arm.com  Wed May 25 09:44:21 2016
From: javi.merino at arm.com (Javi Merino)
Date: Wed, 25 May 2016 17:44:21 +0100
Subject: [PATCH v2 1/5] thermal: Add support for hardware-tracked trip
 points
In-Reply-To: <57451B9C.7070705@gmail.com>
References: <1462268013-14992-1-git-send-email-wxt@rock-chips.com>
 <1462268013-14992-2-git-send-email-wxt@rock-chips.com>
 <20160524125741.GA8979@e104805> <57451B9C.7070705@gmail.com>
Message-ID: <20160525164420.GB11807@e104805>

Hi Caesar,

On Wed, May 25, 2016 at 11:27:24AM +0800, Caesar Wang wrote:
> On 2016?05?24? 20:57, Javi Merino wrote:
> >On Tue, May 03, 2016 at 05:33:29PM +0800, Caesar Wang wrote:
> >>From: Sascha Hauer <s.hauer at pengutronix.de>
> >>
> >>This adds support for hardware-tracked trip points to the device tree
> >>thermal sensor framework.
> >>
> >>The framework supports an arbitrary number of trip points. Whenever
> >>the current temperature is updated, the trip points immediately
> >>below and above the current temperature are found. A .set_trips
> >>callback is then called with the temperatures. If there is no trip
> >>point above or below the current temperature, the passed trip
> >>temperature will be -INT_MAX or INT_MAX respectively. In this callback,
> >>the driver should program the hardware such that it is notified
> >>when either of these trip points are triggered. When a trip point
> >>is triggered, the driver should call `thermal_zone_device_update'
> >>for the respective thermal zone. This will cause the trip points
> >>to be updated again.
> >>
> >>If .set_trips is not implemented, the framework behaves as before.
> >>
> >>This patch is based on an earlier version from Mikko Perttunen
> >><mikko.perttunen at kapsi.fi>
> >>
> >>Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> >>Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> >>Cc: Zhang Rui <rui.zhang at intel.com>
> >>Cc: Eduardo Valentin <edubezval at gmail.com>
> >>Cc: linux-pm at vger.kernel.org
> >>
> >>---
> >>
> >>Changes in v2:
> >>- update the sysfs-api.txt for set_trips
> >>
> >>  Documentation/thermal/sysfs-api.txt |  7 +++++
> >>  drivers/thermal/thermal_core.c      | 52 +++++++++++++++++++++++++++++++++++++
> >>  include/linux/thermal.h             |  3 +++
> >>  3 files changed, 62 insertions(+)
> <cut..>
> >>+	/*
> >>+	 * Set a temperature window. When this window is left the driver
> >>+	 * must inform the thermal core via thermal_zone_device_update.
> >>+	 */
> >>+	ret = tz->ops->set_trips(tz, low, high);
> >>+	if (ret)
> >>+		dev_err(&tz->device, "Failed to set trips: %d\n", ret);
> >This function can be called at the same time from multiple places so
> >it should be reentrant.  I think you should call mutex_lock(tz->lock)
> >before "if (tz->prev_low_trip == low && ..." and unlock it here.
> 
> Sound reasonable, fixes it in next version.
> 
> >>+}
> >>+
> >>  static void update_temperature(struct thermal_zone_device *tz)
> >>  {
> >>  	int temp, ret;
> >>@@ -569,6 +614,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
> >>  	update_temperature(tz);
> >>+	thermal_zone_set_trips(tz);
> >>+
> >>  	for (count = 0; count < tz->trips; count++)
> >>  		handle_thermal_trip(tz, count);
> >>  }
> >>@@ -754,6 +801,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
> >>  	 */
> >>  	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
> >>+	if (!ret)
> >>+		thermal_zone_set_trips(tz);
> >>+
> >You should add a similar call to thermal_zone_set_trips() in trip_point_temp_store()
> 
> No, this patch has been done.
> 
> if you see the linux next kernel.
> 72f3ada UPSTREAM: thermal: trip_point_temp_store() calls
> thermal_zone_device_update()
> 
> --- a/drivers/thermal/thermal_core.c
> +++ b/drivers/thermal/thermal_core.c
> @@ -733,8 +733,12 @@ trip_point_temp_store(struct device *dev,
> struct device_attribute *attr,
> return -EINVAL;
> 
> ret = tz->ops->set_trip_temp(tz, trip, temperature);
> + if (ret)
> + return ret;
> 
> - return ret ? ret : count;
> + thermal_zone_device_update(tz);
> +
> + return count;
> }
> 
> So the "thermal_zone_set_trips(tz)" have been set in
> thermal_zone_device_update.

Ah, right, I missed that.  Thanks!
Javi


From javi.merino at arm.com  Wed May 25 09:47:04 2016
From: javi.merino at arm.com (Javi Merino)
Date: Wed, 25 May 2016 17:47:04 +0100
Subject: [PATCH v3 2/5] thermal: of: implement .set_trips for device tree
 thermal zones
In-Reply-To: <1464148069-26254-3-git-send-email-wxt@rock-chips.com>
References: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
 <1464148069-26254-3-git-send-email-wxt@rock-chips.com>
Message-ID: <20160525164704.GC11807@e104805>

Hi Caesar,

On Wed, May 25, 2016 at 11:47:46AM +0800, Caesar Wang wrote:
> From: Sascha Hauer <s.hauer at pengutronix.de>
> 
> This patch implemnets .set_trips for device tree thermal zones.
             ^
             implements

> As the hardware-tracked trip points is supported by thermal core patch[0].
> 
> patch[0]
> "thermal: Add support for hardware-tracked trip points".
> 
> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> Cc: Zhang Rui <rui.zhang at intel.com>
> Cc: Eduardo Valentin <edubezval at gmail.com>

Other than that, it looks good to me.  You can add my

Reviewed-by: Javi Merino <javi.merino at arm.com>


From robh at kernel.org  Wed May 25 10:32:46 2016
From: robh at kernel.org (Rob Herring)
Date: Wed, 25 May 2016 12:32:46 -0500
Subject: [RESEND PATCH v2] ASoC: rockchip: Add machine driver for
 MAX98357A/RT5514/DA7219
In-Reply-To: <1464053774-15914-1-git-send-email-zhengxing@rock-chips.com>
References: <1464053774-15914-1-git-send-email-zhengxing@rock-chips.com>
Message-ID: <20160525173246.GA5125@rob-hp-laptop>

On Tue, May 24, 2016 at 09:36:14AM +0800, Xing Zheng wrote:
> There are multi codec devices on the RK3399 platform, we can use
> this patch support and control these codecs.
> 
> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
> ---
> 
> Changes in v2:
> - use the FS 256 to set mclks of the max98357a and rt5514 danamically
> - add more sample rate for da7219
> 
>  .../sound/rockchip-max98357a-rt5514-da7219.txt     |   15 +
>  sound/soc/rockchip/Kconfig                         |   11 +
>  sound/soc/rockchip/Makefile                        |    2 +
>  .../rockchip/rockchip_max98357a_rt5514_da7219.c    |  333 ++++++++++++++++++++
>  4 files changed, 361 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
>  create mode 100644 sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c
> 
> diff --git a/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
> new file mode 100644
> index 0000000..5928384
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
> @@ -0,0 +1,15 @@
> +ROCKCHIP with MAX98357A/RT5514/DA7219 codecs
> +
> +Required properties:
> +- compatible: "rockchip,rockchip-sound"

This is generic, but the binding seems to be very specific to only 3 
specific codecs. Listing all 3 codecs seems a bit strange. Perhaps a 
name related to the board name would be better.

> +- rockchip,cpu: The phandle of the Rockchip I2S controller that's
> +  connected to the codecs

What's the size? always 3?

> +- rockchip,codec: The phandle of the MAX98357A/RT5514/DA7219 codecs

Please make the size and ordering clear.

> +
> +Example:
> +
> +sound {
> +	compatible = "rockchip,rockchip-sound";
> +	rockchip,cpu = <&i2s0 &i2s0 &i2s1>;
> +	rockchip,codec = <&max98357a &headsetcodec &codec>;
> +};


From robh at kernel.org  Wed May 25 12:11:25 2016
From: robh at kernel.org (Rob Herring)
Date: Wed, 25 May 2016 14:11:25 -0500
Subject: [PATCH 1/5] dt-bindings: document rk3399 rk-timer bindings
In-Reply-To: <1464169802-6033-2-git-send-email-wxt@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-2-git-send-email-wxt@rock-chips.com>
Message-ID: <20160525191125.GA25213@rob-hp-laptop>

On Wed, May 25, 2016 at 05:49:58PM +0800, Caesar Wang wrote:
> From: Huang Tao <huangtao at rock-chips.com>
> 
> Add compatible string for rk3399 because which timer is a little
> different from older SoCs. So rename the file name from
> rockchip,rk3288-timer.txt to rockchip,rk-timer.txt.
> Clarify rockchip,rk3288-timer supported SoCs.
> 
> Signed-off-by: Huang Tao <huangtao at rock-chips.com>
> Cc: Rob Herring <robh+dt at kernel.org>
> Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> ---
> 
>  .../timer/{rockchip,rk3288-timer.txt => rockchip,rk-timer.txt}      | 6 ++++--
>  1 file changed, 4 insertions(+), 2 deletions(-)
>  rename Documentation/devicetree/bindings/timer/{rockchip,rk3288-timer.txt => rockchip,rk-timer.txt} (75%)

Acked-by: Rob Herring <robh at kernel.org>


From smbarber at chromium.org  Wed May 25 17:07:01 2016
From: smbarber at chromium.org (Stephen Barber)
Date: Wed, 25 May 2016 17:07:01 -0700
Subject: [PATCH] clk: rockchip: add a dummy clock for the watchdog pclk on
 rk3399
In-Reply-To: <1464166316-22480-1-git-send-email-zhengxing@rock-chips.com>
References: <1464166316-22480-1-git-send-email-zhengxing@rock-chips.com>
Message-ID: <CADR9n4_D2WdEvj8XdZ_yW4n5-K6jeDWkhZJbGbmeR59zvyUp+w@mail.gmail.com>

On Wed, May 25, 2016 at 1:51 AM, Xing Zheng <zhengxing at rock-chips.com> wrote:
> Like rk3288, the pclk supplying the watchdog is controlled via the
> SGRF register area. Additionally the SGRF isn't even writable in
> every boot mode.
>
> But still the clock control is available and in the future someone
> might want to use it. Therefore define a simple clock for the time
> being so that the watchdog driver can read its rate.
>
> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
> ---
>
>  drivers/clk/rockchip/clk-rk3399.c |    9 +++++++++
>  1 file changed, 9 insertions(+)
>
> diff --git a/drivers/clk/rockchip/clk-rk3399.c b/drivers/clk/rockchip/clk-rk3399.c
> index 291543f..b6742fa 100644
> --- a/drivers/clk/rockchip/clk-rk3399.c
> +++ b/drivers/clk/rockchip/clk-rk3399.c
> @@ -1498,6 +1498,7 @@ static void __init rk3399_clk_init(struct device_node *np)
>  {
>         struct rockchip_clk_provider *ctx;
>         void __iomem *reg_base;
> +       struct clk *clk;
>
>         reg_base = of_iomap(np, 0);
>         if (!reg_base) {
> @@ -1511,6 +1512,14 @@ static void __init rk3399_clk_init(struct device_node *np)
>                 return;
>         }
>
> +       /* Watchdog pclk is controlled by RK3399 SECURE_GRF_SOC_CON3[8]. */
> +       clk = clk_register_fixed_factor(NULL, "pclk_wdt", "pclk_alive", 0, 1, 1);
> +       if (IS_ERR(clk))
> +               pr_warn("%s: could not register clock pclk_wdt: %ld\n",
> +                       __func__, PTR_ERR(clk));
> +       else
> +               rockchip_clk_add_lookup(ctx, clk, PCLK_WDT);
> +
>         rockchip_clk_register_plls(ctx, rk3399_pll_clks,
>                                    ARRAY_SIZE(rk3399_pll_clks), -1);
>
> --
> 1.7.9.5
>
>

Reviewed-by: Stephen Barber <smbarber at chromium.org>

Steve


From wxt at rock-chips.com  Wed May 25 17:34:34 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Thu, 26 May 2016 08:34:34 +0800
Subject: [PATCH v3 1/5] thermal: Add support for hardware-tracked trip
 points
In-Reply-To: <20160525164258.GA11807@e104805>
References: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
 <1464148069-26254-2-git-send-email-wxt@rock-chips.com>
 <20160525164258.GA11807@e104805>
Message-ID: <5746449A.7070803@rock-chips.com>


On 2016?05?26? 00:42, Javi Merino wrote:
> Hi Caesar,
>
> On Wed, May 25, 2016 at 11:47:45AM +0800, Caesar Wang wrote:
>> From: Sascha Hauer <s.hauer at pengutronix.de>
>>
>> This adds support for hardware-tracked trip points to the device tree
>> thermal sensor framework.
>>
>> The framework supports an arbitrary number of trip points. Whenever
>> the current temperature is updated, the trip points immediately
>> below and above the current temperature are found. A .set_trips
>> callback is then called with the temperatures. If there is no trip
>> point above or below the current temperature, the passed trip
>> temperature will be -INT_MAX or INT_MAX respectively. In this callback,
>> the driver should program the hardware such that it is notified
>> when either of these trip points are triggered. When a trip point
>> is triggered, the driver should call `thermal_zone_device_update'
>> for the respective thermal zone. This will cause the trip points
>> to be updated again.
>>
>> If .set_trips is not implemented, the framework behaves as before.
>>
>> This patch is based on an earlier version from Mikko Perttunen
>> <mikko.perttunen at kapsi.fi>
>>
>> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>> Cc: Zhang Rui <rui.zhang at intel.com>
>> Cc: Eduardo Valentin <edubezval at gmail.com>
>> Cc: linux-pm at vger.kernel.org
>>
>> ---
>>
>> Changes in v3:
>> - as Javi comments on https://patchwork.kernel.org/patch/9001281/.
>> - add the lock for preventing the called from multi placce
>> - add the note for pre_low/high_trip.
>>
>> Changes in v2:
>> - update the sysfs-api.txt for set_trips.
>>
>>   Documentation/thermal/sysfs-api.txt |  7 +++++
>>   drivers/thermal/thermal_core.c      | 52 +++++++++++++++++++++++++++++++++++++
>>   include/linux/thermal.h             |  7 +++++
>>   3 files changed, 66 insertions(+)
>>
>> diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
>> index efc3f3d..75d8838 100644
>> --- a/Documentation/thermal/sysfs-api.txt
>> +++ b/Documentation/thermal/sysfs-api.txt
>> @@ -49,6 +49,9 @@ temperature) and throttle appropriate devices.
>>   	.bind: bind the thermal zone device with a thermal cooling device.
>>   	.unbind: unbind the thermal zone device with a thermal cooling device.
>>   	.get_temp: get the current temperature of the thermal zone.
>> +	.set_trips: set the trip points window. Whenever the current temperature
>> +		    is updated, the trip points immediately below and above the
>> +		    current temperature are found.
>>   	.get_mode: get the current mode (enabled/disabled) of the thermal zone.
>>   	    - "enabled" means the kernel thermal management is enabled.
>>   	    - "disabled" will prevent kernel thermal driver action upon trip points
>> @@ -95,6 +98,10 @@ temperature) and throttle appropriate devices.
>>   			get_temp:	a pointer to a function that reads the
>>   					sensor temperature. This is mandatory
>>   					callback provided by sensor driver.
>> +			set_trips:      a pointer to a function that sets a
>> +					temperature window. When this window is
>> +					left the driver must inform the thermal
>> +					core via thermal_zone_device_update.
>>   			get_trend: 	a pointer to a function that reads the
>>   					sensor temperature trend.
>>   			set_emul_temp:	a pointer to a function that sets
>> diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
>> index 5133cd1..e5bfbd3 100644
>> --- a/drivers/thermal/thermal_core.c
>> +++ b/drivers/thermal/thermal_core.c
>> @@ -520,6 +520,51 @@ exit:
>>   }
>>   EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
>>   
>> +static void thermal_zone_set_trips(struct thermal_zone_device *tz)
>> +{
>> +	int low = -INT_MAX;
>> +	int high = INT_MAX;
>> +	int trip_temp, hysteresis;
>> +	int temp = tz->temperature;
>> +	int i, ret;
>> +
>> +	if (!tz->ops->set_trips)
>> +		return;
>> +
>> +	for (i = 0; i < tz->trips; i++) {
>> +		int trip_low;
>> +
>> +		tz->ops->get_trip_temp(tz, i, &trip_temp);
>> +		tz->ops->get_trip_hyst(tz, i, &hysteresis);
>> +
>> +		trip_low = trip_temp - hysteresis;
>> +
>> +		if (trip_low < temp && trip_low > low)
>> +			low = trip_low;
>> +
>> +		if (trip_temp > temp && trip_temp < high)
>> +			high = trip_temp;
>> +	}
>> +
>> +	/* No need to change trip points */
>> +	if (tz->prev_low_trip == low && tz->prev_high_trip == high)
>> +		return;
>> +
>> +	tz->prev_low_trip = low;
>> +	tz->prev_high_trip = high;
>> +
>> +	dev_dbg(&tz->device, "new temperature boundaries: %d < x < %d\n",
>> +			low, high);
>> +
>> +	/*
>> +	 * Set a temperature window. When this window is left the driver
>> +	 * must inform the thermal core via thermal_zone_device_update.
>> +	 */
>> +	ret = tz->ops->set_trips(tz, low, high);
>> +	if (ret)
>> +		dev_err(&tz->device, "Failed to set trips: %d\n", ret);
> In the v2 review
> (http://article.gmane.org/gmane.linux.documentation/38442) you agreed
> to add locking but you haven't done it.  Maybe you sent the wrong
> version?

My god!
Yep, I remember to change it. Somehow why ...

Thanks Javi for looking over it.

Hoping the next version is the final version.:-)

-Caesar

>
> Cheers,
> Javi
>
> _______________________________________________
> Linux-rockchip mailing list
> Linux-rockchip at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-rockchip


-- 
caesar wang | software engineer | wxt at rock-chip.com




From shawn.lin at rock-chips.com  Wed May 25 18:55:07 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 26 May 2016 09:55:07 +0800
Subject: [PATCH v6 0/5] Add enhanced strobe support for emmc version 5.1 or
 later
Message-ID: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>


Hello all,

This patch is going to support enhanced strobe function
for emmc version 5.1+ introduced by JEDEC recently.

Enchanced strobe is a optional function, so we add a new cap* for drivers to
decide whether to use it.

When introduing hs400 mode, JEDEC asks controllers to use data strobe line
to latch the data from emmc devives. But for cmd-reponse, not mentioned yet.
Since emmc version 5.1 published, JEDEC adds enhanced strobe function to deal
with cmd-response the same way as data-read. This feature is optional.

>From the spec(section 6.6.2.3), the standard scenario to select HS400 enhanced
strobe mode illustrated like this:
(1) set HS_TIMIMG (Highspeed)
(2) Host change freq to <= 52Mhz
(3) set the bus width to Enhanced strobe and DDR8Bit(CMD6), EXT_CSD[183] = 0x86
instead of 0x80
(4) set HS_TIMING to 0x3 (HS400)
(5) Host change freq to <= 200Mhz
(6) Host select HS400 enhanced strobe complete

I can't find a upstreamed controller claimed to support it, as well as the
mmc stack. But my "arasan,sdhci-5.1" actually supports this function. So I decide
to work for this part.

By looking into the SDHCI spec, I find there isn't any registers to enable the
enhanced strobe function. But from my "arasan,sdhci-5.1" databook, it describes a
register called VENDOR_REGISTER(0x78) to trigger this mode. So I guess other sdhci
variant drivers may also need s vendor specific register to deal with it.

If we are sure that our controller supports enhanced strobe mode, just add
mmc-hs400-enhanced-strobe in DT. Once emmc devices claims to support this mode,
we enable it automatically. Of course, other sdhci*/non-sdhci drivers should
implement/overwrite the hs400_enhanced_strobe by themselves. I believe all of the
platforms which need to support this mode should do some basic preparation for their
controllers. Currently I just limit the callback within ths scope of arasan,sdhci-5.1,
but I prone to believe arasan will use VENDOR_REGISTER to tirgger this mode from now on
because I do believe vendor will consider the registers' compatibility.

With this patchset applied, we can successfully run in HS400 enhanced strobe mode on
RK3399 platform with Samsung eMMC KLMBG2JENB-B041(v5.1, 16GB).

mmc1: new HS400 Enhanced strobe MMC card at address 0001
mmcblk0: mmc1:0001 AJNB4R 14.6 GiB
mmcblk0boot0: mmc1:0001 AJNB4R partition 1 4.00 MiB
mmcblk0boot1: mmc1:0001 AJNB4R partition 2 4.00 MiB
mmcblk0rpmb: mmc1:0001 AJNB4R partition 3 4.00 MiB

Also I check this patchset with removing some caps to make sure
all the init sequences for hs400/hs200/DDR52/HighSpeed are correct.


Changes in v6:
- add Doug's test-tag and Jaehoon's review-test-tag
- add Doug's review-test-tag and Jaehoon's test-tag
- a minor string assignment

Changes in v5:
- avoid to call hs400_enhanced+_strobe in mmc_set_initial_state
  if no setting MMC_CAP2_HS400_ES.
- add Adrian's ack for patch[5/5]

Changes in v4:
- check avail_type with EXT_CSD_CARD_TYPE_HS400 instead of
  card_type
- check if host support 8-bit when selecting hs400es
- some minor fix suggested by Douglas and add his review tag

Changes in v3:
- remove helper function and shorten cap2 to MMC_CAP2_HS400_ES
- rename callback to hs400_enhanced_strobe and make it return void
- add enhanced_strobe in mmc_ios and pass it to hs400_enhanced_strobe
- disable host's enhanced strobe in mmc_set_initial_state
- remove bus checking after switching hs400es
- add new function for hs400es timing selection
- fix wrong judgement of mmc_card_hs400es

Changes in v2:
- switch to HS400ES from Highspeed mode directly

Shawn Lin (5):
  Documentation: mmc: add mmc-hs400-enhanced-strobe
  mmc: core: add mmc-hs400-enhanced-strobe support
  mmc: core: implement enhanced strobe support
  mmc: debugfs: add HS400 enhanced strobe description
  mmc: sdhci-of-arasan: implement enhanced strobe callback

 Documentation/devicetree/bindings/mmc/mmc.txt |  1 +
 drivers/mmc/core/bus.c                        |  3 +-
 drivers/mmc/core/core.c                       |  9 +++
 drivers/mmc/core/debugfs.c                    |  3 +-
 drivers/mmc/core/host.c                       |  2 +
 drivers/mmc/core/mmc.c                        | 84 ++++++++++++++++++++++++++-
 drivers/mmc/host/sdhci-of-arasan.c            | 20 +++++++
 include/linux/mmc/card.h                      |  1 +
 include/linux/mmc/host.h                      | 12 ++++
 include/linux/mmc/mmc.h                       |  3 +
 10 files changed, 134 insertions(+), 4 deletions(-)

-- 
2.3.7




From shawn.lin at rock-chips.com  Wed May 25 18:56:02 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 26 May 2016 09:56:02 +0800
Subject: [PATCH v6 1/5] Documentation: mmc: add mmc-hs400-enhanced-strobe
In-Reply-To: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
References: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1464227762-30661-1-git-send-email-shawn.lin@rock-chips.com>

mmc-hs400-enhanced-strobe is used to claim that the
host can support hs400 mode with enhanced strobe
introduced by emmc 5.1 spec.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

Acked-by: Rob Herring <robh at kernel.org>
Reviewed-by: Douglas Anderson <dianders at chromium.org>
---

Changes in v6:
- add Doug's review-tag

Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 Documentation/devicetree/bindings/mmc/mmc.txt | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/mmc/mmc.txt b/Documentation/devicetree/bindings/mmc/mmc.txt
index ed23b9b..ecc007a 100644
--- a/Documentation/devicetree/bindings/mmc/mmc.txt
+++ b/Documentation/devicetree/bindings/mmc/mmc.txt
@@ -46,6 +46,7 @@ Optional properties:
 - mmc-hs200-1_2v: eMMC HS200 mode(1.2V I/O) is supported
 - mmc-hs400-1_8v: eMMC HS400 mode(1.8V I/O) is supported
 - mmc-hs400-1_2v: eMMC HS400 mode(1.2V I/O) is supported
+- mmc-hs400-enhanced-strobe: eMMC HS400 enhanced strobe mode is supported
 - dsr: Value the card's (optional) Driver Stage Register (DSR) should be
   programmed with. Valid range: [0 .. 0xffff].
 
-- 
2.3.7




From shawn.lin at rock-chips.com  Wed May 25 18:56:12 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 26 May 2016 09:56:12 +0800
Subject: [PATCH v6 2/5] mmc: core: add mmc-hs400-enhanced-strobe support
In-Reply-To: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
References: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1464227772-31255-1-git-send-email-shawn.lin@rock-chips.com>

This patch introduce mmc-hs400-enhanced-strobe for platforms
which want to enable enhanced strobe function from DT if the
mmc host controller claims to support enhanced strobe.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

Reviewed-by: Douglas Anderson <dianders at chromium.org>
Tested-by: Jaehoon Chung <jh80.chung at samsung.com>
---

Changes in v6:
- add Doug's review-tag and Jaehoon's test-tag

Changes in v5:
- avoid to call hs400_enhanced+_strobe in mmc_set_initial_state
  if no setting MMC_CAP2_HS400_ES.
- add Adrian's ack for patch[5/5]

Changes in v4:
- check avail_type with EXT_CSD_CARD_TYPE_HS400 instead of
  card_type
- check if host support 8-bit when selecting hs400es
- some minor fix suggested by Douglas and add his review tag

Changes in v3:
- remove helper function and shorten cap2 to MMC_CAP2_HS400_ES
- rename callback to hs400_enhanced_strobe and make it return void
- add enhanced_strobe in mmc_ios and pass it to hs400_enhanced_strobe
- disable host's enhanced strobe in mmc_set_initial_state
- remove bus checking after switching hs400es
- add new function for hs400es timing selection
- fix wrong judgement of mmc_card_hs400es

Changes in v2:
- switch to HS400ES from Highspeed mode directly

 drivers/mmc/core/host.c  | 2 ++
 include/linux/mmc/host.h | 1 +
 2 files changed, 3 insertions(+)

diff --git a/drivers/mmc/core/host.c b/drivers/mmc/core/host.c
index e0a3ee1..45773e4 100644
--- a/drivers/mmc/core/host.c
+++ b/drivers/mmc/core/host.c
@@ -289,6 +289,8 @@ int mmc_of_parse(struct mmc_host *host)
 		host->caps2 |= MMC_CAP2_HS400_1_8V | MMC_CAP2_HS200_1_8V_SDR;
 	if (of_property_read_bool(np, "mmc-hs400-1_2v"))
 		host->caps2 |= MMC_CAP2_HS400_1_2V | MMC_CAP2_HS200_1_2V_SDR;
+	if (of_property_read_bool(np, "mmc-hs400-enhanced-strobe"))
+		host->caps2 |= MMC_CAP2_HS400_ES;
 
 	host->dsr_req = !of_property_read_u32(np, "dsr", &host->dsr);
 	if (host->dsr_req && (host->dsr & ~0xffff)) {
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 85800b4..2a06fb0 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -302,6 +302,7 @@ struct mmc_host {
 #define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
 #define MMC_CAP2_NO_WRITE_PROTECT (1 << 18)	/* No physical write protect pin, assume that card is always read-write */
 #define MMC_CAP2_NO_SDIO	(1 << 19)	/* Do not send SDIO commands during initialization */
+#define MMC_CAP2_HS400_ES	(1 << 20)	/* Host supports enhanced strobe */
 
 	mmc_pm_flag_t		pm_caps;	/* supported pm features */
 
-- 
2.3.7




From shawn.lin at rock-chips.com  Wed May 25 18:56:22 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 26 May 2016 09:56:22 +0800
Subject: [PATCH v6 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
References: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1464227782-31296-1-git-send-email-shawn.lin@rock-chips.com>

Controllers use data strobe line to latch data from devices
under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
introduces enhanced strobe mode for latching cmd response from
emmc devices to host controllers. This new feature is optional,
so it depends both on device's cap and host's cap to decide
whether to use it or not.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

Reviewed-by: Jaehoon Chung <jh80.chung at samsung.com>
Tested-by: Douglas Anderson <dianders at chromium.org>
Tested-by: Jaehoon Chung <jh80.chung at samsung.com>
---

Changes in v6:
- add Doug's test-tag and Jaehoon's review-test-tag

Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/mmc/core/bus.c   |  3 +-
 drivers/mmc/core/core.c  |  9 ++++++
 drivers/mmc/core/mmc.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/mmc/card.h |  1 +
 include/linux/mmc/host.h | 11 +++++++
 include/linux/mmc/mmc.h  |  3 ++
 6 files changed, 108 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 4bc48f1..c64266f 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
 			mmc_card_ddr52(card) ? "DDR " : "",
 			type);
 	} else {
-		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
+		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
 			mmc_hostname(card->host),
 			mmc_card_uhs(card) ? "ultra high speed " :
 			(mmc_card_hs(card) ? "high speed " : ""),
 			mmc_card_hs400(card) ? "HS400 " :
 			(mmc_card_hs200(card) ? "HS200 " : ""),
+			mmc_card_hs400es(card) ? "Enhanced strobe " : "",
 			mmc_card_ddr52(card) ? "DDR " : "",
 			uhs_bus_speed_mode, type, card->rca);
 	}
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 99275e4..b0c1f07 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1127,6 +1127,15 @@ void mmc_set_initial_state(struct mmc_host *host)
 	host->ios.bus_width = MMC_BUS_WIDTH_1;
 	host->ios.timing = MMC_TIMING_LEGACY;
 	host->ios.drv_type = 0;
+	host->ios.enhanced_strobe = false;
+
+	/*
+	 * Make sure we are in non-enhanced strobe mode before we
+	 * actually enable it in ext_csd.
+	 */
+	if ((host->caps2 & MMC_CAP2_HS400_ES) &&
+	     host->ops->hs400_enhanced_strobe)
+		host->ops->hs400_enhanced_strobe(host, &host->ios);
 
 	mmc_set_ios(host);
 }
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index f99c47e..9dc91ba 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
 		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
 	}
 
+	if ((caps2 & MMC_CAP2_HS400_ES) &&
+	    card->ext_csd.strobe_support &&
+	    (avail_type & EXT_CSD_CARD_TYPE_HS400))
+		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
+
 	card->ext_csd.hs_max_dtr = hs_max_dtr;
 	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
 	card->mmc_avail_type = avail_type;
@@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
 			mmc_card_set_blockaddr(card);
 	}
 
+	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
 	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
 	mmc_select_card_type(card);
 
@@ -1216,6 +1222,78 @@ out_err:
 	return err;
 }
 
+static int mmc_select_hs400es(struct mmc_card *card)
+{
+	struct mmc_host *host = card->host;
+	int err = 0;
+	u8 val;
+
+	if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
+		err = -ENOTSUPP;
+		goto out_err;
+	}
+
+	err = mmc_select_bus_width(card);
+	if (IS_ERR_VALUE(err))
+		goto out_err;
+
+	/* Switch card to HS mode */
+	err = mmc_select_hs(card);
+	if (err) {
+		pr_err("%s: switch to high-speed failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	err = mmc_switch_status(card);
+	if (err)
+		goto out_err;
+
+	/* Switch card to DDR with strobe bit */
+	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
+	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			 EXT_CSD_BUS_WIDTH,
+			 val,
+			 card->ext_csd.generic_cmd6_time);
+	if (err) {
+		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	/* Switch card to HS400 */
+	val = EXT_CSD_TIMING_HS400 |
+	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
+	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
+			   EXT_CSD_HS_TIMING, val,
+			   card->ext_csd.generic_cmd6_time,
+			   true, false, true);
+	if (err) {
+		pr_err("%s: switch to hs400es failed, err:%d\n",
+			mmc_hostname(host), err);
+		goto out_err;
+	}
+
+	/* Set host controller to HS400 timing and frequency */
+	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
+
+	/* Controller enable enhanced strobe function */
+	host->ios.enhanced_strobe = true;
+	if (host->ops->hs400_enhanced_strobe)
+		host->ops->hs400_enhanced_strobe(host, &host->ios);
+
+	err = mmc_switch_status(card);
+	if (err)
+		goto out_err;
+
+	return 0;
+
+out_err:
+	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
+	       __func__, err);
+	return err;
+}
+
 static void mmc_select_driver_type(struct mmc_card *card)
 {
 	int card_drv_type, drive_strength, drv_type;
@@ -1297,7 +1375,7 @@ err:
 }
 
 /*
- * Activate High Speed or HS200 mode if supported.
+ * Activate High Speed, HS200 or HS400ES mode if supported.
  */
 static int mmc_select_timing(struct mmc_card *card)
 {
@@ -1306,7 +1384,9 @@ static int mmc_select_timing(struct mmc_card *card)
 	if (!mmc_can_ext_csd(card))
 		goto bus_speed;
 
-	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
+	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
+		err = mmc_select_hs400es(card);
+	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
 		err = mmc_select_hs200(card);
 	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
 		err = mmc_select_hs(card);
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index eb0151b..22defc2 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -95,6 +95,7 @@ struct mmc_ext_csd {
 	u8			raw_partition_support;	/* 160 */
 	u8			raw_rpmb_size_mult;	/* 168 */
 	u8			raw_erased_mem_count;	/* 181 */
+	u8			strobe_support;		/* 184 */
 	u8			raw_ext_csd_structure;	/* 194 */
 	u8			raw_card_type;		/* 196 */
 	u8			raw_driver_strength;	/* 197 */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 2a06fb0..0eabb72 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -19,6 +19,7 @@
 
 #include <linux/mmc/core.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/mmc.h>
 #include <linux/mmc/pm.h>
 
 struct mmc_ios {
@@ -77,6 +78,8 @@ struct mmc_ios {
 #define MMC_SET_DRIVER_TYPE_A	1
 #define MMC_SET_DRIVER_TYPE_C	2
 #define MMC_SET_DRIVER_TYPE_D	3
+
+	bool enhanced_strobe;			/* hs400es selection */
 };
 
 struct mmc_host_ops {
@@ -143,6 +146,9 @@ struct mmc_host_ops {
 
 	/* Prepare HS400 target operating frequency depending host driver */
 	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
+	/* Prepare enhanced strobe depending host driver */
+	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
+					 struct mmc_ios *ios);
 	int	(*select_drive_strength)(struct mmc_card *card,
 					 unsigned int max_dtr, int host_drv,
 					 int card_drv, int *drv_type);
@@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
 	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
 }
 
+static inline bool mmc_card_hs400es(struct mmc_card *card)
+{
+	return card->host->ios.enhanced_strobe;
+}
+
 void mmc_retune_timer_stop(struct mmc_host *host);
 
 static inline void mmc_retune_needed(struct mmc_host *host)
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 15f2c4a..c376209 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -297,6 +297,7 @@ struct _mmc_csd {
 #define EXT_CSD_PART_CONFIG		179	/* R/W */
 #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
 #define EXT_CSD_BUS_WIDTH		183	/* R/W */
+#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
 #define EXT_CSD_HS_TIMING		185	/* R/W */
 #define EXT_CSD_POWER_CLASS		187	/* R/W */
 #define EXT_CSD_REV			192	/* RO */
@@ -380,12 +381,14 @@ struct _mmc_csd {
 #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
 #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
 					 EXT_CSD_CARD_TYPE_HS400_1_2V)
+#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
 
 #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
 #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
 #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
 #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
 #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
+#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
 
 #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
 #define EXT_CSD_TIMING_HS	1	/* High speed */
-- 
2.3.7




From shawn.lin at rock-chips.com  Wed May 25 18:56:30 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 26 May 2016 09:56:30 +0800
Subject: [PATCH v6 4/5] mmc: debugfs: add HS400 enhanced strobe description
In-Reply-To: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
References: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1464227790-31337-1-git-send-email-shawn.lin@rock-chips.com>

We introduce HS400 with enhanced strobe function, so we need
to add it for debug show.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

Reviewed-by: Douglas Anderson <dianders at chromium.org>
Tested-by: Douglas Anderson <dianders at chromium.org>
Tested-by: Jaehoon Chung <jh80.chung at samsung.com>
---

Changes in v6:
- add Doug's review-test-tag and Jaehoon's test-tag
- a minor string assignment

Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/mmc/core/debugfs.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 9382a57..c8451ce 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -148,7 +148,8 @@ static int mmc_ios_show(struct seq_file *s, void *data)
 		str = "mmc HS200";
 		break;
 	case MMC_TIMING_MMC_HS400:
-		str = "mmc HS400";
+		str = mmc_card_hs400es(host->card) ?
+			"mmc HS400 enhanced strobe" : "mmc HS400";
 		break;
 	default:
 		str = "invalid";
-- 
2.3.7




From shawn.lin at rock-chips.com  Wed May 25 18:56:43 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 26 May 2016 09:56:43 +0800
Subject: [PATCH v6 5/5] mmc: sdhci-of-arasan: implement enhanced strobe
 callback
In-Reply-To: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
References: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1464227803-31380-1-git-send-email-shawn.lin@rock-chips.com>

Currently sdhci-arasan 5.1 can support enhanced strobe function,
and we now limit it just for "arasan,sdhci-5.1". Add
mmc-hs400-enhanced-strobe in DT to enable the function if we're
sure our controller can support it.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

Acked-by: Adrian Hunter <adrian.hunter at intel.com>
Reviewed-by: Doug Anderson <dianders at chromium.org>
Tested-by: Doug Anderson <dianders at chromium.org>
---

Changes in v6:
- add Doug's test-tag

Changes in v5: None
Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/mmc/host/sdhci-of-arasan.c | 20 ++++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index b6f4c1d..533e2bc 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -25,7 +25,9 @@
 #include "sdhci-pltfm.h"
 
 #define SDHCI_ARASAN_CLK_CTRL_OFFSET	0x2c
+#define SDHCI_ARASAN_VENDOR_REGISTER	0x78
 
+#define VENDOR_ENHANCED_STROBE		BIT(0)
 #define CLK_CTRL_TIMEOUT_SHIFT		16
 #define CLK_CTRL_TIMEOUT_MASK		(0xf << CLK_CTRL_TIMEOUT_SHIFT)
 #define CLK_CTRL_TIMEOUT_MIN_EXP	13
@@ -79,6 +81,21 @@ static void sdhci_arasan_set_clock(struct sdhci_host *host, unsigned int clock)
 	}
 }
 
+static void sdhci_arasan_hs400_enhanced_strobe(struct mmc_host *mmc,
+					struct mmc_ios *ios)
+{
+	u32 vendor;
+	struct sdhci_host *host = mmc_priv(mmc);
+
+	vendor = readl(host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
+	if (ios->enhanced_strobe)
+		vendor |= VENDOR_ENHANCED_STROBE;
+	else
+		vendor &= ~VENDOR_ENHANCED_STROBE;
+
+	writel(vendor, host->ioaddr + SDHCI_ARASAN_VENDOR_REGISTER);
+}
+
 static struct sdhci_ops sdhci_arasan_ops = {
 	.set_clock = sdhci_arasan_set_clock,
 	.get_max_clock = sdhci_pltfm_clk_get_max_clock,
@@ -245,6 +262,9 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
 			dev_err(&pdev->dev, "phy_power_on err.\n");
 			goto err_phy_power;
 		}
+
+		host->mmc_host_ops.hs400_enhanced_strobe =
+					sdhci_arasan_hs400_enhanced_strobe;
 	}
 
 	ret = sdhci_add_host(host);
-- 
2.3.7




From shawn.lin at rock-chips.com  Wed May 25 19:23:39 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 26 May 2016 10:23:39 +0800
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <573DBAA5.2070706@samsung.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
 <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
 <573BCC8D.5090606@kernel-upstream.org>
 <CAD=FV=VneQR3wurjezBkRhtQiH+q-FfhDN8=Ym=XqtZpVmsdUw@mail.gmail.com>
 <573C3283.1040606@rock-chips.com>
 <CAD=FV=UoT2GRYWJWXEn_ccvKGgC+PzQM_BCtLHAa7jxzbaQ9SA@mail.gmail.com>
 <10b3dc0e-aebf-664b-b36b-c54692cd9983@rock-chips.com>
 <573DBAA5.2070706@samsung.com>
Message-ID: <4d8f3992-a1d3-6010-4964-8ca13cddc1c5@rock-chips.com>

Hi Jaehoon,

On 2016/5/19 21:07, Jaehoon Chung wrote:
> On 05/19/2016 08:31 PM, Shawn Lin wrote:
>> Hi,
>>
>> On 2016/5/19 1:37, Doug Anderson wrote:
>>> Hi,
>>>
>>> On Wed, May 18, 2016 at 2:14 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>>> Hi
>>>>
>>>>
>>>> On 2016-5-18 12:12, Doug Anderson wrote:
>>>>>
>>>>> Hi,
>>>>>
>>>>> On Tue, May 17, 2016 at 6:59 PM, Shawn Lin
>>>>> <shawn.lin at kernel-upstream.org> wrote:
>>>>>>
>>>>>> Could you try this patch to see if you can still find HLE?
>>>>>>
>>>>>> @@ -2356,12 +2356,22 @@ static void dw_mci_cmd_interrupt(struct dw_mci
>>>>>> *host, u32 status)
>>>>>>   static void dw_mci_handle_cd(struct dw_mci *host)
>>>>>>   {
>>>>>>          int i;
>>>>>> +       int present;
>>>>>>
>>>>>>          for (i = 0; i < host->num_slots; i++) {
>>>>>>                  struct dw_mci_slot *slot = host->slot[i];
>>>>>>
>>>>>>                  if (!slot)
>>>>>>                          continue;
>>>>>>
>>>>>> +               present = !(mci_readl(slot->host, CDETECT) & (1 <<
>>>>>> slot->id));
>>>>>> +               if (present)
>>>>>> +                       set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>>>>> +               else
>>>>>> +                       clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>>>>
>>>>>
>>>>> No, because we don't use the builtin card detect on veyron.  ;)
>>>>>
>>>>> We use GPIO card detect because we didn't like the way JTAG and SD
>>>>> interacted.  Also on rk3288 the builtin card detect line had the wrong
>>>>> voltage domain (you couldn't detect a card when the IO lines were
>>>>> powered off).  The builtin card detect line is always driven low on
>>>>> veyron.
>>>>
>>>>
>>>> Okay, I see.
>>>>
>>>>>
>>>>>
>>>>> I'm nearly certain that the root cause of my HLE errors is actually
>>>>> related to the same problem addressed by the commit 7c5209c315ea
>>>>> ("mmc: core: Increase delay for voltage to stabilize from 3.3V to
>>>>> 1.8V").  I think that on minnie we're still on the hairy edge and
>>>>> sometimes the line doesn't transition fast enough.
>>>>
>>>>
>>>> Things are not so simple from your details.
>>>>
>>>> I was not enabling SD3.0 support, then I also found HLE sometimes.
>>>> So it seems commit 7c5209c315ea does not contibute to this phenomenon.
>>>
>>> Just to clarify, in my case commit 7c5209c315ea didn't make the
>>> problem worse, but made it better.  Just not better enough.  ;)
>>>
>>>
>>>> The scenario looks like:
>>>> remove sd-card -> mmc_sd_detect -> send status(CMD13) ->power_off ->
>>>> set_ios -> setup_bus -> disabled clk , then HLE irq storm coming
>>>>
>>>> From the code of dw_mci_prepare_command:
>>>> SDMMC_CMD_PRV_DAT_WAIT will not be used for CMD13, so we don't
>>>> wait_busy here, then cmd code is loding into queue of dw_mmc but
>>>> still failing send out because it's in busy?
>>>>
>>>> With my patch, things go well:
>>>> remove sd-card -> clear bit of DW_MMC_CARD_PRESENT  -> send
>>>> status(CMD13) return directly -> power_off -> set_ios -> setup_bus ->
>>>> disable clk
>>>>
>>>> So why should we allow inquiry of card status if we sure the card is
>>>> removed? I mean no any further cmds should be delivered.
>>>
>>> Quite honestly just dealing with the HLE error (my patch or
>>> equivalent) might be a sane solution for the problem you describe.
>>
>> Yes, your patch looks good to me, so it should be merged firstly. :)
>> Then let's push it a bit further more that when HLEs are coming,
>> somethings must be wrong(currently I don't see a obvious clue from
>> the code itself although, I'm prone to think it belongs to the
>> software issue).
>
> We don't know what's main cause for HLE..But i also think it's relevant to SW issue.
> But we need to consider all possibilities..
>
>>
>>
>>>
>>> dw_mmc needs to be able to work with an external card detect GPIO.
>>> It's been part of the dw_mmc driver for a long time and is (in fact)
>>> in use upstream at least by rk3288-veyron.  Any solution that only
>>> works for internal card detect is not enough.  Just handling the HLE
>>> error to deal with the interrupt storm and then letting Linux remove
>>> the card (because of the card detect interrupt) seems totally OK to
>>> me.
>>>
>>
>> Sure, some of rockchip Socs use gpio for CD because they don't
>> have a internal CD, such as RK3036, right?
>>
>>> Note: I'd be very curious if your problems get better if you disable
>>
>> Not at all.
>>
>>> the "grf_force_jtag" bit in the GRF.  If you're using the builtin card
>>> detect and you use the boot default of "grf_force_jtag" then your pins
>>> will be unmuxed behind your back when the card is ejected.  This could
>>> be causing the dw_mmc controller to get confused.
>>
>> Right, grf_force_jtag is also not a friend of mine. :)
>> So I had disabled this function before I was debugging it.
>>
>>>
>>>
>>>> And another question: should we wait busy for cmd13?
>>>
>>> I don't think so.  As I understand it CMD13 uses only the CMD line for
>>> communication and it should be appropriate to send this when the bus
>>> is "busy" (which means that the DATA lines are low).
>>
>> Ahh... take back my question.. I was just considering a wired situation
>> that pins are unmuxed on the background(cmd line as well) when cmd13 is
>> delivering....
>>
>>
>>>
>>> Also: it seems odd that the HLE IRQ storm didn't come right after the
>>> CMD 13 in your description above.  Are you sure it was the CMD 13 that
>>> caused the HLEs, or could it has been something else?
>>
>> Actually no. Any cmds be issued can trigger HLEs, I think, after sd card is removed When I hacked mmc_sd_detecd to send other cmds intead
>> of cmd13.
>>
>> From dw_mmc databook v270a(7.2.3 Clock Programming) we can see:
>> The DWC_mobile_storage loads each of these registers only when the
>> start_cmd bit and the Update_clk_regs_only bit in the CMD register are
>> set. When a command is successfully loaded, the DWC_mobile_storage
>> clears this bit, unless the DWC_mobile_storage already has another
>> command in the queue, at which point it gives an HLE (Hardware Locked
>> Error); for details on HLEs, refer to ?Error Handling? on page 233.
>> Software should look for the start_cmd and the Update_clk_regs_only
>> bits, and should also set the wait_prvdata_complete bit to ensure that
>> clock parameters do not change during data transfer.
>>
>> Maybe the cmd is trying to load(or somethings wrong with the
>> controller?) when we disable the clk? That may explain my observation
>> that HLEs came after disabling clk.
>
> I agreed.
>
> To Disable clock, it sends cmd with update_clk_regs_only and wait_prvdata_complete bit.
> I think it's problem..(waiting for prvdata..)
>
> If there are ongoing some data(read/write), then before disabling clock, waiting for completing previous data.
> (But card was already removed, and it couldn't do anything.)
> It's difficult to analyze the HLE..So After applying first, then we can solve this problem, step by step.
>

I saw you send a PR for v4.7-fix to Ulf which didn't include this one.
Do you plan to add it into 4.8 materials? :)

> Best Regards,
> Jaehoon Chung
>
>>
>>
>>>
>>>
>>> -Doug
>>>
>>>
>>>
>>
>>
>
>
>
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Wed May 25 20:07:43 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 26 May 2016 11:07:43 +0800
Subject: [RFC PATCH 1/2] mmc: dw_mmc: remove redundant of set_bit and clear_bit
Message-ID: <1464232063-24841-1-git-send-email-shawn.lin@rock-chips.com>

dw_mci_get_cd have already dealed with these for
both of internal card-detect and gpio card-detect.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

---

 drivers/mmc/host/dw_mmc.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 829a6ee..cb30e91 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2616,10 +2616,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 		mmc->max_seg_size = mmc->max_req_size;
 	}
 
-	if (dw_mci_get_cd(mmc))
-		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-	else
-		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+	dw_mci_get_cd(mmc);
 
 	ret = mmc_add_host(mmc);
 	if (ret)
-- 
2.3.7




From shawn.lin at rock-chips.com  Wed May 25 20:08:11 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 26 May 2016 11:08:11 +0800
Subject: [RFC PATCH 2/2] mmc: dw_mmc: check card present before starting
 request
Message-ID: <1464232091-24882-1-git-send-email-shawn.lin@rock-chips.com>

The main reason to add this check is to avoid unnecessary
mmc_request if the card is removed. Although we have already
check this in dw_mci_handle_cd for runtime usage of sd card and
dw_mci_init_slot for noremovable devices, but there is a timing
gap before it really calls dw_mci_get_cd as mmc_detect_change needs
some delay here.

Another gain here is that we could save some checkings of card status
after sd card been removed.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

 drivers/mmc/host/dw_mmc.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index cb30e91..2940d24 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -105,6 +105,7 @@ struct idmac_desc {
 static bool dw_mci_reset(struct dw_mci *host);
 static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
 static int dw_mci_card_busy(struct mmc_host *mmc);
+static int dw_mci_get_cd(struct mmc_host *mmc);
 
 #if defined(CONFIG_DEBUG_FS)
 static int dw_mci_req_show(struct seq_file *s, void *v)
@@ -1248,6 +1249,8 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 
 	WARN_ON(slot->mrq);
 
+	dw_mci_get_cd(mmc);
+
 	/*
 	 * The check for card presence and queueing of the request must be
 	 * atomic, otherwise the card could be removed in between and the
-- 
2.3.7




From jh80.chung at samsung.com  Wed May 25 20:59:07 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Thu, 26 May 2016 12:59:07 +0900
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <4d8f3992-a1d3-6010-4964-8ca13cddc1c5@rock-chips.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
 <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
 <573BCC8D.5090606@kernel-upstream.org>
 <CAD=FV=VneQR3wurjezBkRhtQiH+q-FfhDN8=Ym=XqtZpVmsdUw@mail.gmail.com>
 <573C3283.1040606@rock-chips.com>
 <CAD=FV=UoT2GRYWJWXEn_ccvKGgC+PzQM_BCtLHAa7jxzbaQ9SA@mail.gmail.com>
 <10b3dc0e-aebf-664b-b36b-c54692cd9983@rock-chips.com>
 <573DBAA5.2070706@samsung.com>
 <CGME20160526022412epcas1p1408431e9596aaf84e8b58510ee81d4c4@epcas1p1.samsung.com>
 <4d8f3992-a1d3-6010-4964-8ca13cddc1c5@rock-chips.com>
Message-ID: <5746748B.7080305@samsung.com>

On 05/26/2016 11:23 AM, Shawn Lin wrote:
> Hi Jaehoon,
> 
> On 2016/5/19 21:07, Jaehoon Chung wrote:
>> On 05/19/2016 08:31 PM, Shawn Lin wrote:
>>> Hi,
>>>
>>> On 2016/5/19 1:37, Doug Anderson wrote:
>>>> Hi,
>>>>
>>>> On Wed, May 18, 2016 at 2:14 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>>>> Hi
>>>>>
>>>>>
>>>>> On 2016-5-18 12:12, Doug Anderson wrote:
>>>>>>
>>>>>> Hi,
>>>>>>
>>>>>> On Tue, May 17, 2016 at 6:59 PM, Shawn Lin
>>>>>> <shawn.lin at kernel-upstream.org> wrote:
>>>>>>>
>>>>>>> Could you try this patch to see if you can still find HLE?
>>>>>>>
>>>>>>> @@ -2356,12 +2356,22 @@ static void dw_mci_cmd_interrupt(struct dw_mci
>>>>>>> *host, u32 status)
>>>>>>>   static void dw_mci_handle_cd(struct dw_mci *host)
>>>>>>>   {
>>>>>>>          int i;
>>>>>>> +       int present;
>>>>>>>
>>>>>>>          for (i = 0; i < host->num_slots; i++) {
>>>>>>>                  struct dw_mci_slot *slot = host->slot[i];
>>>>>>>
>>>>>>>                  if (!slot)
>>>>>>>                          continue;
>>>>>>>
>>>>>>> +               present = !(mci_readl(slot->host, CDETECT) & (1 <<
>>>>>>> slot->id));
>>>>>>> +               if (present)
>>>>>>> +                       set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>>>>>> +               else
>>>>>>> +                       clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>>>>>
>>>>>>
>>>>>> No, because we don't use the builtin card detect on veyron.  ;)
>>>>>>
>>>>>> We use GPIO card detect because we didn't like the way JTAG and SD
>>>>>> interacted.  Also on rk3288 the builtin card detect line had the wrong
>>>>>> voltage domain (you couldn't detect a card when the IO lines were
>>>>>> powered off).  The builtin card detect line is always driven low on
>>>>>> veyron.
>>>>>
>>>>>
>>>>> Okay, I see.
>>>>>
>>>>>>
>>>>>>
>>>>>> I'm nearly certain that the root cause of my HLE errors is actually
>>>>>> related to the same problem addressed by the commit 7c5209c315ea
>>>>>> ("mmc: core: Increase delay for voltage to stabilize from 3.3V to
>>>>>> 1.8V").  I think that on minnie we're still on the hairy edge and
>>>>>> sometimes the line doesn't transition fast enough.
>>>>>
>>>>>
>>>>> Things are not so simple from your details.
>>>>>
>>>>> I was not enabling SD3.0 support, then I also found HLE sometimes.
>>>>> So it seems commit 7c5209c315ea does not contibute to this phenomenon.
>>>>
>>>> Just to clarify, in my case commit 7c5209c315ea didn't make the
>>>> problem worse, but made it better.  Just not better enough.  ;)
>>>>
>>>>
>>>>> The scenario looks like:
>>>>> remove sd-card -> mmc_sd_detect -> send status(CMD13) ->power_off ->
>>>>> set_ios -> setup_bus -> disabled clk , then HLE irq storm coming
>>>>>
>>>>> From the code of dw_mci_prepare_command:
>>>>> SDMMC_CMD_PRV_DAT_WAIT will not be used for CMD13, so we don't
>>>>> wait_busy here, then cmd code is loding into queue of dw_mmc but
>>>>> still failing send out because it's in busy?
>>>>>
>>>>> With my patch, things go well:
>>>>> remove sd-card -> clear bit of DW_MMC_CARD_PRESENT  -> send
>>>>> status(CMD13) return directly -> power_off -> set_ios -> setup_bus ->
>>>>> disable clk
>>>>>
>>>>> So why should we allow inquiry of card status if we sure the card is
>>>>> removed? I mean no any further cmds should be delivered.
>>>>
>>>> Quite honestly just dealing with the HLE error (my patch or
>>>> equivalent) might be a sane solution for the problem you describe.
>>>
>>> Yes, your patch looks good to me, so it should be merged firstly. :)
>>> Then let's push it a bit further more that when HLEs are coming,
>>> somethings must be wrong(currently I don't see a obvious clue from
>>> the code itself although, I'm prone to think it belongs to the
>>> software issue).
>>
>> We don't know what's main cause for HLE..But i also think it's relevant to SW issue.
>> But we need to consider all possibilities..
>>
>>>
>>>
>>>>
>>>> dw_mmc needs to be able to work with an external card detect GPIO.
>>>> It's been part of the dw_mmc driver for a long time and is (in fact)
>>>> in use upstream at least by rk3288-veyron.  Any solution that only
>>>> works for internal card detect is not enough.  Just handling the HLE
>>>> error to deal with the interrupt storm and then letting Linux remove
>>>> the card (because of the card detect interrupt) seems totally OK to
>>>> me.
>>>>
>>>
>>> Sure, some of rockchip Socs use gpio for CD because they don't
>>> have a internal CD, such as RK3036, right?
>>>
>>>> Note: I'd be very curious if your problems get better if you disable
>>>
>>> Not at all.
>>>
>>>> the "grf_force_jtag" bit in the GRF.  If you're using the builtin card
>>>> detect and you use the boot default of "grf_force_jtag" then your pins
>>>> will be unmuxed behind your back when the card is ejected.  This could
>>>> be causing the dw_mmc controller to get confused.
>>>
>>> Right, grf_force_jtag is also not a friend of mine. :)
>>> So I had disabled this function before I was debugging it.
>>>
>>>>
>>>>
>>>>> And another question: should we wait busy for cmd13?
>>>>
>>>> I don't think so.  As I understand it CMD13 uses only the CMD line for
>>>> communication and it should be appropriate to send this when the bus
>>>> is "busy" (which means that the DATA lines are low).
>>>
>>> Ahh... take back my question.. I was just considering a wired situation
>>> that pins are unmuxed on the background(cmd line as well) when cmd13 is
>>> delivering....
>>>
>>>
>>>>
>>>> Also: it seems odd that the HLE IRQ storm didn't come right after the
>>>> CMD 13 in your description above.  Are you sure it was the CMD 13 that
>>>> caused the HLEs, or could it has been something else?
>>>
>>> Actually no. Any cmds be issued can trigger HLEs, I think, after sd card is removed When I hacked mmc_sd_detecd to send other cmds intead
>>> of cmd13.
>>>
>>> From dw_mmc databook v270a(7.2.3 Clock Programming) we can see:
>>> The DWC_mobile_storage loads each of these registers only when the
>>> start_cmd bit and the Update_clk_regs_only bit in the CMD register are
>>> set. When a command is successfully loaded, the DWC_mobile_storage
>>> clears this bit, unless the DWC_mobile_storage already has another
>>> command in the queue, at which point it gives an HLE (Hardware Locked
>>> Error); for details on HLEs, refer to ?Error Handling? on page 233.
>>> Software should look for the start_cmd and the Update_clk_regs_only
>>> bits, and should also set the wait_prvdata_complete bit to ensure that
>>> clock parameters do not change during data transfer.
>>>
>>> Maybe the cmd is trying to load(or somethings wrong with the
>>> controller?) when we disable the clk? That may explain my observation
>>> that HLEs came after disabling clk.
>>
>> I agreed.
>>
>> To Disable clock, it sends cmd with update_clk_regs_only and wait_prvdata_complete bit.
>> I think it's problem..(waiting for prvdata..)
>>
>> If there are ongoing some data(read/write), then before disabling clock, waiting for completing previous data.
>> (But card was already removed, and it couldn't do anything.)
>> It's difficult to analyze the HLE..So After applying first, then we can solve this problem, step by step.
>>
> 
> I saw you send a PR for v4.7-fix to Ulf which didn't include this one.
> Do you plan to add it into 4.8 materials? :)

Yes, I think good that this is prepared for next. (Will apply on this weekend.)
Do you have other opinion? :)

If you have other opinion, i will reflect yours. Thanks!

Best Regards,
Jaehoon Chung

> 
>> Best Regards,
>> Jaehoon Chung
>>
>>>
>>>
>>>>
>>>>
>>>> -Doug
>>>>
>>>>
>>>>
>>>
>>>
>>
>>
>>
>>
> 
> 



From shawn.lin at rock-chips.com  Wed May 25 21:07:25 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Thu, 26 May 2016 12:07:25 +0800
Subject: [PATCH] mmc: dw_mmc: Consider HLE errors to be data and command
 errors
In-Reply-To: <5746748B.7080305@samsung.com>
References: <1426002490-2014-1-git-send-email-dianders@chromium.org>
 <5502CA4E.9060401@samsung.com>
 <CAD=FV=VX3ix-j4y95W1q8b-aVuVEN+4xsd8WLx2xcE7KPNJwRw@mail.gmail.com>
 <5506707D.40708@samsung.com> <55189F04.8000404@samsung.com>
 <CAD=FV=WFAZqAsXOqunt0fxw87M-FruwUrxuzW0MJsG6UvfSjzA@mail.gmail.com>
 <CAD=FV=UJGcwa_biSCGhD=kS-T+fppCniBFfOHb5ohnwSwSwMMA@mail.gmail.com>
 <573BCC8D.5090606@kernel-upstream.org>
 <CAD=FV=VneQR3wurjezBkRhtQiH+q-FfhDN8=Ym=XqtZpVmsdUw@mail.gmail.com>
 <573C3283.1040606@rock-chips.com>
 <CAD=FV=UoT2GRYWJWXEn_ccvKGgC+PzQM_BCtLHAa7jxzbaQ9SA@mail.gmail.com>
 <10b3dc0e-aebf-664b-b36b-c54692cd9983@rock-chips.com>
 <573DBAA5.2070706@samsung.com>
 <CGME20160526022412epcas1p1408431e9596aaf84e8b58510ee81d4c4@epcas1p1.samsung.com>
 <4d8f3992-a1d3-6010-4964-8ca13cddc1c5@rock-chips.com>
 <5746748B.7080305@samsung.com>
Message-ID: <10d2520b-0919-0a5b-f5b6-23b133e63dbb@rock-chips.com>

? 2016/5/26 11:59, Jaehoon Chung ??:
> On 05/26/2016 11:23 AM, Shawn Lin wrote:
>> Hi Jaehoon,
>>
>> On 2016/5/19 21:07, Jaehoon Chung wrote:
>>> On 05/19/2016 08:31 PM, Shawn Lin wrote:
>>>> Hi,
>>>>
>>>> On 2016/5/19 1:37, Doug Anderson wrote:
>>>>> Hi,
>>>>>
>>>>> On Wed, May 18, 2016 at 2:14 AM, Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>>>>> Hi
>>>>>>
>>>>>>
>>>>>> On 2016-5-18 12:12, Doug Anderson wrote:
>>>>>>>
>>>>>>> Hi,
>>>>>>>
>>>>>>> On Tue, May 17, 2016 at 6:59 PM, Shawn Lin
>>>>>>> <shawn.lin at kernel-upstream.org> wrote:
>>>>>>>>
>>>>>>>> Could you try this patch to see if you can still find HLE?
>>>>>>>>
>>>>>>>> @@ -2356,12 +2356,22 @@ static void dw_mci_cmd_interrupt(struct dw_mci
>>>>>>>> *host, u32 status)
>>>>>>>>   static void dw_mci_handle_cd(struct dw_mci *host)
>>>>>>>>   {
>>>>>>>>          int i;
>>>>>>>> +       int present;
>>>>>>>>
>>>>>>>>          for (i = 0; i < host->num_slots; i++) {
>>>>>>>>                  struct dw_mci_slot *slot = host->slot[i];
>>>>>>>>
>>>>>>>>                  if (!slot)
>>>>>>>>                          continue;
>>>>>>>>
>>>>>>>> +               present = !(mci_readl(slot->host, CDETECT) & (1 <<
>>>>>>>> slot->id));
>>>>>>>> +               if (present)
>>>>>>>> +                       set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>>>>>>> +               else
>>>>>>>> +                       clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>>>>>>>
>>>>>>>
>>>>>>> No, because we don't use the builtin card detect on veyron.  ;)
>>>>>>>
>>>>>>> We use GPIO card detect because we didn't like the way JTAG and SD
>>>>>>> interacted.  Also on rk3288 the builtin card detect line had the wrong
>>>>>>> voltage domain (you couldn't detect a card when the IO lines were
>>>>>>> powered off).  The builtin card detect line is always driven low on
>>>>>>> veyron.
>>>>>>
>>>>>>
>>>>>> Okay, I see.
>>>>>>
>>>>>>>
>>>>>>>
>>>>>>> I'm nearly certain that the root cause of my HLE errors is actually
>>>>>>> related to the same problem addressed by the commit 7c5209c315ea
>>>>>>> ("mmc: core: Increase delay for voltage to stabilize from 3.3V to
>>>>>>> 1.8V").  I think that on minnie we're still on the hairy edge and
>>>>>>> sometimes the line doesn't transition fast enough.
>>>>>>
>>>>>>
>>>>>> Things are not so simple from your details.
>>>>>>
>>>>>> I was not enabling SD3.0 support, then I also found HLE sometimes.
>>>>>> So it seems commit 7c5209c315ea does not contibute to this phenomenon.
>>>>>
>>>>> Just to clarify, in my case commit 7c5209c315ea didn't make the
>>>>> problem worse, but made it better.  Just not better enough.  ;)
>>>>>
>>>>>
>>>>>> The scenario looks like:
>>>>>> remove sd-card -> mmc_sd_detect -> send status(CMD13) ->power_off ->
>>>>>> set_ios -> setup_bus -> disabled clk , then HLE irq storm coming
>>>>>>
>>>>>> From the code of dw_mci_prepare_command:
>>>>>> SDMMC_CMD_PRV_DAT_WAIT will not be used for CMD13, so we don't
>>>>>> wait_busy here, then cmd code is loding into queue of dw_mmc but
>>>>>> still failing send out because it's in busy?
>>>>>>
>>>>>> With my patch, things go well:
>>>>>> remove sd-card -> clear bit of DW_MMC_CARD_PRESENT  -> send
>>>>>> status(CMD13) return directly -> power_off -> set_ios -> setup_bus ->
>>>>>> disable clk
>>>>>>
>>>>>> So why should we allow inquiry of card status if we sure the card is
>>>>>> removed? I mean no any further cmds should be delivered.
>>>>>
>>>>> Quite honestly just dealing with the HLE error (my patch or
>>>>> equivalent) might be a sane solution for the problem you describe.
>>>>
>>>> Yes, your patch looks good to me, so it should be merged firstly. :)
>>>> Then let's push it a bit further more that when HLEs are coming,
>>>> somethings must be wrong(currently I don't see a obvious clue from
>>>> the code itself although, I'm prone to think it belongs to the
>>>> software issue).
>>>
>>> We don't know what's main cause for HLE..But i also think it's relevant to SW issue.
>>> But we need to consider all possibilities..
>>>
>>>>
>>>>
>>>>>
>>>>> dw_mmc needs to be able to work with an external card detect GPIO.
>>>>> It's been part of the dw_mmc driver for a long time and is (in fact)
>>>>> in use upstream at least by rk3288-veyron.  Any solution that only
>>>>> works for internal card detect is not enough.  Just handling the HLE
>>>>> error to deal with the interrupt storm and then letting Linux remove
>>>>> the card (because of the card detect interrupt) seems totally OK to
>>>>> me.
>>>>>
>>>>
>>>> Sure, some of rockchip Socs use gpio for CD because they don't
>>>> have a internal CD, such as RK3036, right?
>>>>
>>>>> Note: I'd be very curious if your problems get better if you disable
>>>>
>>>> Not at all.
>>>>
>>>>> the "grf_force_jtag" bit in the GRF.  If you're using the builtin card
>>>>> detect and you use the boot default of "grf_force_jtag" then your pins
>>>>> will be unmuxed behind your back when the card is ejected.  This could
>>>>> be causing the dw_mmc controller to get confused.
>>>>
>>>> Right, grf_force_jtag is also not a friend of mine. :)
>>>> So I had disabled this function before I was debugging it.
>>>>
>>>>>
>>>>>
>>>>>> And another question: should we wait busy for cmd13?
>>>>>
>>>>> I don't think so.  As I understand it CMD13 uses only the CMD line for
>>>>> communication and it should be appropriate to send this when the bus
>>>>> is "busy" (which means that the DATA lines are low).
>>>>
>>>> Ahh... take back my question.. I was just considering a wired situation
>>>> that pins are unmuxed on the background(cmd line as well) when cmd13 is
>>>> delivering....
>>>>
>>>>
>>>>>
>>>>> Also: it seems odd that the HLE IRQ storm didn't come right after the
>>>>> CMD 13 in your description above.  Are you sure it was the CMD 13 that
>>>>> caused the HLEs, or could it has been something else?
>>>>
>>>> Actually no. Any cmds be issued can trigger HLEs, I think, after sd card is removed When I hacked mmc_sd_detecd to send other cmds intead
>>>> of cmd13.
>>>>
>>>> From dw_mmc databook v270a(7.2.3 Clock Programming) we can see:
>>>> The DWC_mobile_storage loads each of these registers only when the
>>>> start_cmd bit and the Update_clk_regs_only bit in the CMD register are
>>>> set. When a command is successfully loaded, the DWC_mobile_storage
>>>> clears this bit, unless the DWC_mobile_storage already has another
>>>> command in the queue, at which point it gives an HLE (Hardware Locked
>>>> Error); for details on HLEs, refer to ?Error Handling? on page 233.
>>>> Software should look for the start_cmd and the Update_clk_regs_only
>>>> bits, and should also set the wait_prvdata_complete bit to ensure that
>>>> clock parameters do not change during data transfer.
>>>>
>>>> Maybe the cmd is trying to load(or somethings wrong with the
>>>> controller?) when we disable the clk? That may explain my observation
>>>> that HLEs came after disabling clk.
>>>
>>> I agreed.
>>>
>>> To Disable clock, it sends cmd with update_clk_regs_only and wait_prvdata_complete bit.
>>> I think it's problem..(waiting for prvdata..)
>>>
>>> If there are ongoing some data(read/write), then before disabling clock, waiting for completing previous data.
>>> (But card was already removed, and it couldn't do anything.)
>>> It's difficult to analyze the HLE..So After applying first, then we can solve this problem, step by step.
>>>
>>
>> I saw you send a PR for v4.7-fix to Ulf which didn't include this one.
>> Do you plan to add it into 4.8 materials? :)
>
> Yes, I think good that this is prepared for next. (Will apply on this weekend.)
> Do you have other opinion? :)

No, thanks. I just wanna make sure this one will be merged. :)

>
> If you have other opinion, i will reflect yours. Thanks!
>
> Best Regards,
> Jaehoon Chung
>
>>
>>> Best Regards,
>>> Jaehoon Chung
>>>
>>>>
>>>>
>>>>>
>>>>>
>>>>> -Doug
>>>>>
>>>>>
>>>>>
>>>>
>>>>
>>>
>>>
>>>
>>>
>>
>>
>
>
>
>


-- 
Best Regards
Shawn Lin



From wxt at rock-chips.com  Wed May 25 21:17:20 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Thu, 26 May 2016 12:17:20 +0800
Subject: [PATCH v3 1/5] thermal: Add support for hardware-tracked trip
 points
In-Reply-To: <5746449A.7070803@rock-chips.com>
References: <1464148069-26254-1-git-send-email-wxt@rock-chips.com>
 <1464148069-26254-2-git-send-email-wxt@rock-chips.com>
 <20160525164258.GA11807@e104805> <5746449A.7070803@rock-chips.com>
Message-ID: <574678D0.1080301@rock-chips.com>


On 2016?05?26? 08:34, Caesar Wang wrote:
>
> On 2016?05?26? 00:42, Javi Merino wrote:
>> Hi Caesar,
>>
>> On Wed, May 25, 2016 at 11:47:45AM +0800, Caesar Wang wrote:
>>> From: Sascha Hauer <s.hauer at pengutronix.de>
>>>
>>> This adds support for hardware-tracked trip points to the device tree
>>> thermal sensor framework.
>>>
>>> The framework supports an arbitrary number of trip points. Whenever
>>> the current temperature is updated, the trip points immediately
>>> below and above the current temperature are found. A .set_trips
>>> callback is then called with the temperatures. If there is no trip
>>> point above or below the current temperature, the passed trip
>>> temperature will be -INT_MAX or INT_MAX respectively. In this callback,
>>> the driver should program the hardware such that it is notified
>>> when either of these trip points are triggered. When a trip point
>>> is triggered, the driver should call `thermal_zone_device_update'
>>> for the respective thermal zone. This will cause the trip points
>>> to be updated again.
>>>
>>> If .set_trips is not implemented, the framework behaves as before.
>>>
>>> This patch is based on an earlier version from Mikko Perttunen
>>> <mikko.perttunen at kapsi.fi>
>>>
>>> Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
>>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>>> Cc: Zhang Rui <rui.zhang at intel.com>
>>> Cc: Eduardo Valentin <edubezval at gmail.com>
>>> Cc: linux-pm at vger.kernel.org
>>>
>>> ---
>>>
>>> Changes in v3:
>>> - as Javi comments on https://patchwork.kernel.org/patch/9001281/.
>>> - add the lock for preventing the called from multi placce
>>> - add the note for pre_low/high_trip.
>>>
>>> Changes in v2:
>>> - update the sysfs-api.txt for set_trips.
>>>
>>>   Documentation/thermal/sysfs-api.txt |  7 +++++
>>>   drivers/thermal/thermal_core.c      | 52 
>>> +++++++++++++++++++++++++++++++++++++
>>>   include/linux/thermal.h             |  7 +++++
>>>   3 files changed, 66 insertions(+)
>>>
>>> diff --git a/Documentation/thermal/sysfs-api.txt 
>>> b/Documentation/thermal/sysfs-api.txt
>>> index efc3f3d..75d8838 100644
>>> --- a/Documentation/thermal/sysfs-api.txt
>>> +++ b/Documentation/thermal/sysfs-api.txt
>>> @@ -49,6 +49,9 @@ temperature) and throttle appropriate devices.
>>>       .bind: bind the thermal zone device with a thermal cooling 
>>> device.
>>>       .unbind: unbind the thermal zone device with a thermal cooling 
>>> device.
>>>       .get_temp: get the current temperature of the thermal zone.
>>> +    .set_trips: set the trip points window. Whenever the current 
>>> temperature
>>> +            is updated, the trip points immediately below and above 
>>> the
>>> +            current temperature are found.
>>>       .get_mode: get the current mode (enabled/disabled) of the 
>>> thermal zone.
>>>           - "enabled" means the kernel thermal management is enabled.
>>>           - "disabled" will prevent kernel thermal driver action 
>>> upon trip points
>>> @@ -95,6 +98,10 @@ temperature) and throttle appropriate devices.
>>>               get_temp:    a pointer to a function that reads the
>>>                       sensor temperature. This is mandatory
>>>                       callback provided by sensor driver.
>>> +            set_trips:      a pointer to a function that sets a
>>> +                    temperature window. When this window is
>>> +                    left the driver must inform the thermal
>>> +                    core via thermal_zone_device_update.
>>>               get_trend:     a pointer to a function that reads the
>>>                       sensor temperature trend.
>>>               set_emul_temp:    a pointer to a function that sets
>>> diff --git a/drivers/thermal/thermal_core.c 
>>> b/drivers/thermal/thermal_core.c
>>> index 5133cd1..e5bfbd3 100644
>>> --- a/drivers/thermal/thermal_core.c
>>> +++ b/drivers/thermal/thermal_core.c
>>> @@ -520,6 +520,51 @@ exit:
>>>   }
>>>   EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
>>>   +static void thermal_zone_set_trips(struct thermal_zone_device *tz)
>>> +{
>>> +    int low = -INT_MAX;
>>> +    int high = INT_MAX;
>>> +    int trip_temp, hysteresis;
>>> +    int temp = tz->temperature;
>>> +    int i, ret;
>>> +
>>> +    if (!tz->ops->set_trips)
>>> +        return;
>>> +
>>> +    for (i = 0; i < tz->trips; i++) {
>>> +        int trip_low;
>>> +
>>> +        tz->ops->get_trip_temp(tz, i, &trip_temp);
>>> +        tz->ops->get_trip_hyst(tz, i, &hysteresis);
>>> +
>>> +        trip_low = trip_temp - hysteresis;
>>> +
>>> +        if (trip_low < temp && trip_low > low)
>>> +            low = trip_low;
>>> +
>>> +        if (trip_temp > temp && trip_temp < high)
>>> +            high = trip_temp;
>>> +    }
>>> +
>>> +    /* No need to change trip points */
>>> +    if (tz->prev_low_trip == low && tz->prev_high_trip == high)
>>> +        return;
>>> +
>>> +    tz->prev_low_trip = low;
>>> +    tz->prev_high_trip = high;
>>> +
>>> +    dev_dbg(&tz->device, "new temperature boundaries: %d < x < %d\n",
>>> +            low, high);
>>> +
>>> +    /*
>>> +     * Set a temperature window. When this window is left the driver
>>> +     * must inform the thermal core via thermal_zone_device_update.
>>> +     */
>>> +    ret = tz->ops->set_trips(tz, low, high);
>>> +    if (ret)
>>> +        dev_err(&tz->device, "Failed to set trips: %d\n", ret);
>> In the v2 review
>> (http://article.gmane.org/gmane.linux.documentation/38442) you agreed
>> to add locking but you haven't done it.  Maybe you sent the wrong
>> version?
>
> My god!
> Yep, I remember to change it. Somehow why ...
>
> Thanks Javi for looking over it.
>
> Hoping the next version is the final version.:-)
>

If add the lock, there is a deadlock for board,  maybe I will keep to 
stay with this version.

   2.895038] [ INFO: possible recursive locking detected ]
[    2.900459] 4.4.4 #56 Not tainted
[    2.903774] ---------------------------------------------
[    2.909171] swapper/0/1 is trying to acquire lock:
[    2.913974]  (&tz->lock){+.+.+.}, at: [<ffffffc00069b428>] 
handle_thermal_trip+0x230/0x304
[    2.922336]
[    2.922336] but task is already holding lock:
[    2.928166]  (&tz->lock){+.+.+.}, at: [<ffffffc000699194>] 
thermal_zone_set_trips+0xd8/0x180
[    2.936670]
[    2.936670] other info that might help us debug this:
[    2.943199]  Possible unsafe locking scenario:
[    2.943199]
[    2.949117]        CPU0
[    2.951565]        ----
[    2.954012]   lock(&tz->lock);
[    2.957098]   lock(&tz->lock);
[    2.960176]
[    2.960176]  *** DEADLOCK ***
[    2.960176]
[    2.966098]  May be due to missing lock nesting notation
[    2.966098]
[    2.972885] 3 locks held by swapper/0/1:
[    2.976809]  #0:  (&dev->mutex){......}, at: [<ffffffc0005920b0>] 
__driver_attach+0x40/0xa8
[    2.985243]  #1:  (&dev->mutex){......}, at: [<ffffffc0005920d8>] 
__driver_attach+0x68/0xa8
[    2.993671]  #2:  (&tz->lock){+.+.+.}, at: [<ffffffc000699194>] 
thermal_zone_set_trips+0xd8/0x180
...







> -Caesar
>
>>
>> Cheers,
>> Javi
>>
>> _______________________________________________
>> Linux-rockchip mailing list
>> Linux-rockchip at lists.infradead.org
>> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
>

-- 
caesar wang | software engineer | wxt at rock-chip.com




From zhengxing at rock-chips.com  Thu May 26 02:04:39 2016
From: zhengxing at rock-chips.com (Xing Zheng)
Date: Thu, 26 May 2016 17:04:39 +0800
Subject: [RESEND PATCH v2] ASoC: rockchip: Add machine driver for
 MAX98357A/RT5514/DA7219
In-Reply-To: <20160525173246.GA5125@rob-hp-laptop>
References: <1464053774-15914-1-git-send-email-zhengxing@rock-chips.com>
 <20160525173246.GA5125@rob-hp-laptop>
Message-ID: <5746BC27.1030008@rock-chips.com>

Hi Rob,

On 2016?05?26? 01:32, Rob Herring wrote:
> On Tue, May 24, 2016 at 09:36:14AM +0800, Xing Zheng wrote:
>> There are multi codec devices on the RK3399 platform, we can use
>> this patch support and control these codecs.
>>
>> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
>> ---
>>
>> Changes in v2:
>> - use the FS 256 to set mclks of the max98357a and rt5514 danamically
>> - add more sample rate for da7219
>>
>>   .../sound/rockchip-max98357a-rt5514-da7219.txt     |   15 +
>>   sound/soc/rockchip/Kconfig                         |   11 +
>>   sound/soc/rockchip/Makefile                        |    2 +
>>   .../rockchip/rockchip_max98357a_rt5514_da7219.c    |  333 ++++++++++++++++++++
>>   4 files changed, 361 insertions(+)
>>   create mode 100644 Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
>>   create mode 100644 sound/soc/rockchip/rockchip_max98357a_rt5514_da7219.c
>>
>> diff --git a/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
>> new file mode 100644
>> index 0000000..5928384
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/sound/rockchip-max98357a-rt5514-da7219.txt
>> @@ -0,0 +1,15 @@
>> +ROCKCHIP with MAX98357A/RT5514/DA7219 codecs
>> +
>> +Required properties:
>> +- compatible: "rockchip,rockchip-sound"
> This is generic, but the binding seems to be very specific to only 3
> specific codecs. Listing all 3 codecs seems a bit strange. Perhaps a
> name related to the board name would be better.
Yes, I think that I should rename to rk3399_max98357a_rt5514_da7219.c, 
it is related to the rk3399 boards.
>> +- rockchip,cpu: The phandle of the Rockchip I2S controller that's
>> +  connected to the codecs
> What's the size? always 3?
Not always 3, the size is limited by machine driver, The similar 
approach with mt8173-rt5650-rt5676.txt.
>> +- rockchip,codec: The phandle of the MAX98357A/RT5514/DA7219 codecs
> Please make the size and ordering clear.
Ditto.

Thanks.

-- 
- Xing Zheng




From ykk at rock-chips.com  Thu May 26 02:34:25 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Thu, 26 May 2016 17:34:25 +0800
Subject: [PATCH v2 0/10] Add RK3399 eDP support and fix some bugs to
 analogix_dp driver.
In-Reply-To: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
Message-ID: <5746C321.9000707@rock-chips.com>

Hi Javier,

On 05/24/2016 01:01 PM, Yakir Yang wrote:
> Hi all,
>
> This series have been posted about one month, still no comments, help here :(
This series works rightly on Rockchip platform, and most of them haven't 
touch the
common analogix_dp driver (except for the hotplug fixed). So i guess 
Exynos platform
should also happy with this changes.

But not sure about that. So, is it possible that you could help to check 
this on Exynos
Chromebook, if so i would be very grateful about that.

Thanks,
- Yakir
>
> RK3399 and RK3288 shared the same eDP IP controller, only some light
> difference with VOP configure and GRF configure.
>
> Also same misc fix to analogix_dp driver:
> - Hotplug invalid which report by Dan Carpenter
> - Make panel detect to an optional action
> - correct the register bit define error in ANALOGIX_DP_PLL_REG_1
>
>
> Changes in v2:
> - new patch in v2
> - rebase with drm-next, fix some conflicts
> - new patch in v2
>
> Yakir Yang (10):
>    drm/bridge: analogix_dp: rename RK3288_DP to ROCKCHIP_DP
>    drm/rockchip: analogix_dp: split the lcdc select setting into device
>      data
>    drm/bridge: analogix_dp: correct the register bit define error in
>      ANALOGIX_DP_PLL_REG_1
>    drm/bridge: analogix_dp: some rockchip chips need to flip REF_CLK bit
>      setting
>    drm/rockchip: analogix_dp: add rk3399 eDP support
>    drm/rockchip: analogix_dp: make panel detect to an optional action
>    drm/bridge: analogix_dp: introduce connector mode_valid callback to
>      plat driver
>    drm/rockchip: analogix_dp: correct the connector display color format
>      and bpc
>    drm/rockchip: analogix_dp: update the comments about why need to
>      hardcode VOP output mode
>    drm/bridge: analogix_dp: fix no drm hpd event when panel plug in
>
>   .../bindings/display/bridge/analogix_dp.txt        |   1 +
>   .../display/rockchip/analogix_dp-rockchip.txt      |   2 +-
>   drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  19 ++-
>   drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |   8 +-
>   drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  |  12 +-
>   drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  |   5 +-
>   drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 157 ++++++++++++++-------
>   include/drm/bridge/analogix_dp.h                   |  10 ++
>   8 files changed, 152 insertions(+), 62 deletions(-)
>




From adrian.hunter at intel.com  Thu May 26 04:04:52 2016
From: adrian.hunter at intel.com (Adrian Hunter)
Date: Thu, 26 May 2016 14:04:52 +0300
Subject: [PATCH v6 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <1464227782-31296-1-git-send-email-shawn.lin@rock-chips.com>
References: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
 <1464227782-31296-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <5746D854.1020200@intel.com>

On 26/05/16 04:56, Shawn Lin wrote:
> Controllers use data strobe line to latch data from devices
> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
> introduces enhanced strobe mode for latching cmd response from
> emmc devices to host controllers. This new feature is optional,
> so it depends both on device's cap and host's cap to decide
> whether to use it or not.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

I have a couple of comments below, but they don't necessarily require any
action, so:

Acked-by: Adrian Hunter <adrian.hunter at intel.com>

> 
> Reviewed-by: Jaehoon Chung <jh80.chung at samsung.com>
> Tested-by: Douglas Anderson <dianders at chromium.org>
> Tested-by: Jaehoon Chung <jh80.chung at samsung.com>
> ---
> 
> Changes in v6:
> - add Doug's test-tag and Jaehoon's review-test-tag
> 
> Changes in v5: None
> Changes in v4: None
> Changes in v3: None
> Changes in v2: None
> 
>  drivers/mmc/core/bus.c   |  3 +-
>  drivers/mmc/core/core.c  |  9 ++++++
>  drivers/mmc/core/mmc.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
>  include/linux/mmc/card.h |  1 +
>  include/linux/mmc/host.h | 11 +++++++
>  include/linux/mmc/mmc.h  |  3 ++
>  6 files changed, 108 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
> index 4bc48f1..c64266f 100644
> --- a/drivers/mmc/core/bus.c
> +++ b/drivers/mmc/core/bus.c
> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			type);
>  	} else {
> -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
> +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>  			mmc_hostname(card->host),
>  			mmc_card_uhs(card) ? "ultra high speed " :
>  			(mmc_card_hs(card) ? "high speed " : ""),
>  			mmc_card_hs400(card) ? "HS400 " :
>  			(mmc_card_hs200(card) ? "HS200 " : ""),
> +			mmc_card_hs400es(card) ? "Enhanced strobe " : "",
>  			mmc_card_ddr52(card) ? "DDR " : "",
>  			uhs_bus_speed_mode, type, card->rca);
>  	}
> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
> index 99275e4..b0c1f07 100644
> --- a/drivers/mmc/core/core.c
> +++ b/drivers/mmc/core/core.c
> @@ -1127,6 +1127,15 @@ void mmc_set_initial_state(struct mmc_host *host)
>  	host->ios.bus_width = MMC_BUS_WIDTH_1;
>  	host->ios.timing = MMC_TIMING_LEGACY;
>  	host->ios.drv_type = 0;
> +	host->ios.enhanced_strobe = false;
> +
> +	/*
> +	 * Make sure we are in non-enhanced strobe mode before we
> +	 * actually enable it in ext_csd.
> +	 */
> +	if ((host->caps2 & MMC_CAP2_HS400_ES) &&
> +	     host->ops->hs400_enhanced_strobe)
> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
>  
>  	mmc_set_ios(host);
>  }
> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
> index f99c47e..9dc91ba 100644
> --- a/drivers/mmc/core/mmc.c
> +++ b/drivers/mmc/core/mmc.c
> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>  		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>  	}
>  
> +	if ((caps2 & MMC_CAP2_HS400_ES) &&
> +	    card->ext_csd.strobe_support &&
> +	    (avail_type & EXT_CSD_CARD_TYPE_HS400))
> +		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
> +
>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>  	card->mmc_avail_type = avail_type;
> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>  			mmc_card_set_blockaddr(card);
>  	}
>  
> +	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>  	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>  	mmc_select_card_type(card);
>  
> @@ -1216,6 +1222,78 @@ out_err:
>  	return err;
>  }
>  
> +static int mmc_select_hs400es(struct mmc_card *card)
> +{
> +	struct mmc_host *host = card->host;
> +	int err = 0;
> +	u8 val;
> +
> +	if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
> +		err = -ENOTSUPP;
> +		goto out_err;
> +	}
> +
> +	err = mmc_select_bus_width(card);
> +	if (IS_ERR_VALUE(err))
> +		goto out_err;
> +
> +	/* Switch card to HS mode */
> +	err = mmc_select_hs(card);
> +	if (err) {
> +		pr_err("%s: switch to high-speed failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;

The spec. says "switch to High Speed mode and then set the clock frequency
to a value not greater than 52 MHz" which would tend to imply changing to
the High Speed frequency here. It shouldn't make any difference, so I don't
know if it is worth doing.

> +
> +	/* Switch card to DDR with strobe bit */
> +	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			 EXT_CSD_BUS_WIDTH,
> +			 val,
> +			 card->ext_csd.generic_cmd6_time);
> +	if (err) {
> +		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	/* Switch card to HS400 */
> +	val = EXT_CSD_TIMING_HS400 |
> +	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
> +	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
> +			   EXT_CSD_HS_TIMING, val,
> +			   card->ext_csd.generic_cmd6_time,
> +			   true, false, true);
> +	if (err) {
> +		pr_err("%s: switch to hs400es failed, err:%d\n",
> +			mmc_hostname(host), err);
> +		goto out_err;
> +	}
> +
> +	/* Set host controller to HS400 timing and frequency */
> +	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
> +
> +	/* Controller enable enhanced strobe function */
> +	host->ios.enhanced_strobe = true;
> +	if (host->ops->hs400_enhanced_strobe)
> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
> +

And again here, if we followed the spec. exactly we would change to the
HS400 frequency here rather than after sending CMD13. Again, it shouldn't
make any difference, so I don't if it is worth doing.

> +	err = mmc_switch_status(card);
> +	if (err)
> +		goto out_err;
> +
> +	return 0;
> +
> +out_err:
> +	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
> +	       __func__, err);
> +	return err;
> +}
> +
>  static void mmc_select_driver_type(struct mmc_card *card)
>  {
>  	int card_drv_type, drive_strength, drv_type;
> @@ -1297,7 +1375,7 @@ err:
>  }
>  
>  /*
> - * Activate High Speed or HS200 mode if supported.
> + * Activate High Speed, HS200 or HS400ES mode if supported.
>   */
>  static int mmc_select_timing(struct mmc_card *card)
>  {
> @@ -1306,7 +1384,9 @@ static int mmc_select_timing(struct mmc_card *card)
>  	if (!mmc_can_ext_csd(card))
>  		goto bus_speed;
>  
> -	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
> +		err = mmc_select_hs400es(card);
> +	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>  		err = mmc_select_hs200(card);
>  	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>  		err = mmc_select_hs(card);
> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
> index eb0151b..22defc2 100644
> --- a/include/linux/mmc/card.h
> +++ b/include/linux/mmc/card.h
> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>  	u8			raw_partition_support;	/* 160 */
>  	u8			raw_rpmb_size_mult;	/* 168 */
>  	u8			raw_erased_mem_count;	/* 181 */
> +	u8			strobe_support;		/* 184 */
>  	u8			raw_ext_csd_structure;	/* 194 */
>  	u8			raw_card_type;		/* 196 */
>  	u8			raw_driver_strength;	/* 197 */
> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
> index 2a06fb0..0eabb72 100644
> --- a/include/linux/mmc/host.h
> +++ b/include/linux/mmc/host.h
> @@ -19,6 +19,7 @@
>  
>  #include <linux/mmc/core.h>
>  #include <linux/mmc/card.h>
> +#include <linux/mmc/mmc.h>
>  #include <linux/mmc/pm.h>
>  
>  struct mmc_ios {
> @@ -77,6 +78,8 @@ struct mmc_ios {
>  #define MMC_SET_DRIVER_TYPE_A	1
>  #define MMC_SET_DRIVER_TYPE_C	2
>  #define MMC_SET_DRIVER_TYPE_D	3
> +
> +	bool enhanced_strobe;			/* hs400es selection */
>  };
>  
>  struct mmc_host_ops {
> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>  
>  	/* Prepare HS400 target operating frequency depending host driver */
>  	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
> +	/* Prepare enhanced strobe depending host driver */
> +	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
> +					 struct mmc_ios *ios);
>  	int	(*select_drive_strength)(struct mmc_card *card,
>  					 unsigned int max_dtr, int host_drv,
>  					 int card_drv, int *drv_type);
> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>  	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>  }
>  
> +static inline bool mmc_card_hs400es(struct mmc_card *card)
> +{
> +	return card->host->ios.enhanced_strobe;
> +}
> +
>  void mmc_retune_timer_stop(struct mmc_host *host);
>  
>  static inline void mmc_retune_needed(struct mmc_host *host)
> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
> index 15f2c4a..c376209 100644
> --- a/include/linux/mmc/mmc.h
> +++ b/include/linux/mmc/mmc.h
> @@ -297,6 +297,7 @@ struct _mmc_csd {
>  #define EXT_CSD_PART_CONFIG		179	/* R/W */
>  #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
>  #define EXT_CSD_BUS_WIDTH		183	/* R/W */
> +#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
>  #define EXT_CSD_HS_TIMING		185	/* R/W */
>  #define EXT_CSD_POWER_CLASS		187	/* R/W */
>  #define EXT_CSD_REV			192	/* RO */
> @@ -380,12 +381,14 @@ struct _mmc_csd {
>  #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
>  #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
>  					 EXT_CSD_CARD_TYPE_HS400_1_2V)
> +#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
>  
>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
>  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
>  #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
>  
>  #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
>  #define EXT_CSD_TIMING_HS	1	/* High speed */
> 



From javier at osg.samsung.com  Thu May 26 05:48:47 2016
From: javier at osg.samsung.com (Javier Martinez Canillas)
Date: Thu, 26 May 2016 08:48:47 -0400
Subject: [PATCH v2 0/10] Add RK3399 eDP support and fix some bugs to
 analogix_dp driver.
In-Reply-To: <5746C321.9000707@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
 <5746C321.9000707@rock-chips.com>
Message-ID: <4e1c65f8-5a5b-dbb9-35fe-ef09c0758536@osg.samsung.com>

Hello Yakir,

On 05/26/2016 05:34 AM, Yakir Yang wrote:
> Hi Javier,
> 
> On 05/24/2016 01:01 PM, Yakir Yang wrote:
>> Hi all,
>>
>> This series have been posted about one month, still no comments, help here :(
> This series works rightly on Rockchip platform, and most of them haven't touch the
> common analogix_dp driver (except for the hotplug fixed). So i guess Exynos platform
> should also happy with this changes.
> 
> But not sure about that. So, is it possible that you could help to check this on Exynos
> Chromebook, if so i would be very grateful about that.
>

Of course, I' ll test. Could you please provide me a branch that I can
pull directly to avoid cherry-picking all the patches from the list? 
 
> Thanks,
> - Yakir
>>

Best regards,
-- 
Javier Martinez Canillas
Open Source Group
Samsung Research America


From zhengxing at rock-chips.com  Thu May 26 06:02:22 2016
From: zhengxing at rock-chips.com (Xing Zheng)
Date: Thu, 26 May 2016 21:02:22 +0800
Subject: [PATCH v3] ASoC: rockchip: Add machine driver for
 MAX98357A/RT5514/DA7219
Message-ID: <1464267742-15312-1-git-send-email-zhengxing@rock-chips.com>

There are multi codec devices on the RK3399 platform, we can use
this patch support and control these codecs.

Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
---

Changes in v3:
- rename DOC to rockchip,rk3399-max98357a-rt5514-da7219.txt
- rename compatible to rockchip,rk3399-max98357a-rt5514-da7219
- rename source code to rk3399_max98357a_rt5514_da7219.c

Changes in v2:
- use the FS 256 to set mclks of the max98357a and rt5514 danamically
- add more sample rate for da7219

 .../rockchip,rk3399-max98357a-rt5514-da7219.txt    |   15 +
 sound/soc/rockchip/Kconfig                         |   11 +
 sound/soc/rockchip/Makefile                        |    2 +
 .../soc/rockchip/rk3399_max98357a_rt5514_da7219.c  |  333 ++++++++++++++++++++
 4 files changed, 361 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3399-max98357a-rt5514-da7219.txt
 create mode 100644 sound/soc/rockchip/rk3399_max98357a_rt5514_da7219.c

diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3399-max98357a-rt5514-da7219.txt b/Documentation/devicetree/bindings/sound/rockchip,rk3399-max98357a-rt5514-da7219.txt
new file mode 100644
index 0000000..3ae603e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip,rk3399-max98357a-rt5514-da7219.txt
@@ -0,0 +1,15 @@
+ROCKCHIP with MAX98357A/RT5514/DA7219 codecs
+
+Required properties:
+- compatible: "rockchip,rk3399-max98357a-rt5514-da7219"
+- rockchip,cpu: The phandle of the Rockchip I2S controller that's
+  connected to the codecs
+- rockchip,codec: The phandle of the MAX98357A/RT5514/DA7219 codecs
+
+Example:
+
+sound {
+	compatible = "rockchip,rk3399-max98357a-rt5514-da7219";
+	rockchip,cpu = <&i2s0 &i2s0 &i2s1>;
+	rockchip,codec = <&max98357a &headsetcodec &codec>;
+};
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index f1e0c70..e5bd1f9 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -41,3 +41,14 @@ config SND_SOC_ROCKCHIP_RT5645
 	help
 	  Say Y or M here if you want to add support for SoC audio on Rockchip
 	  boards using the RT5645/RT5650 codec, such as Veyron.
+
+config SND_SOC_RK3399_MAX98357A_RT5514_DA7219
+	tristate "ASoC support for Rockchip RK3399 boards using the MAX98357A/RT5514/DA7219"
+	depends on SND_SOC_ROCKCHIP && GPIOLIB
+	select SND_SOC_ROCKCHIP_I2S
+	select SND_SOC_MAX98357A
+	select SND_SOC_RT5514
+	select SND_SOC_DA7219
+	help
+	  Say Y or M here if you want to add support for SoC audio on Rockchip RK3399
+	  boards using the MAX98357A/RT5514/DA7219.
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index c0bf560..0d9ca0a 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -7,6 +7,8 @@ obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
 
 snd-soc-rockchip-max98090-objs := rockchip_max98090.o
 snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
+snd-soc-rk3399-max98357a-rt5514-da7219-objs := rk3399_max98357a_rt5514_da7219.o
 
 obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
+obj-$(CONFIG_SND_SOC_RK3399_MAX98357A_RT5514_DA7219) += snd-soc-rk3399-max98357a-rt5514-da7219.o
diff --git a/sound/soc/rockchip/rk3399_max98357a_rt5514_da7219.c b/sound/soc/rockchip/rk3399_max98357a_rt5514_da7219.c
new file mode 100644
index 0000000..ec88600
--- /dev/null
+++ b/sound/soc/rockchip/rk3399_max98357a_rt5514_da7219.c
@@ -0,0 +1,333 @@
+/*
+ * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
+ *
+ * Copyright (c) 2016, ROCKCHIP CORPORATION.  All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/delay.h>
+#include <linux/spi/spi.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "rockchip_i2s.h"
+#include "../codecs/da7219.h"
+#include "../codecs/da7219-aad.h"
+#include "../codecs/rt5514.h"
+
+#define DRV_NAME "rk3399-max98357a-rt5514-da7219"
+
+#define SOUND_FS	256
+
+static struct snd_soc_jack rockchip_sound_jack;
+
+static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
+	SND_SOC_DAPM_HP("Headphones", NULL),
+	SND_SOC_DAPM_SPK("Speakers", NULL),
+	SND_SOC_DAPM_MIC("Headset Mic", NULL),
+	SND_SOC_DAPM_MIC("Int Mic", NULL),
+};
+
+static const struct snd_soc_dapm_route rockchip_dapm_routes[] = {
+	/* Input Lines */
+	{"MIC", NULL, "Headset Mic"},
+	{"DMIC1L", NULL, "Int Mic"},
+	{"DMIC1R", NULL, "Int Mic"},
+
+	/* Output Lines */
+	{"Headphones", NULL, "HPL"},
+	{"Headphones", NULL, "HPR"},
+	{"Speakers", NULL, "Speakers"},
+};
+
+static const struct snd_kcontrol_new rockchip_controls[] = {
+	SOC_DAPM_PIN_SWITCH("Headphones"),
+	SOC_DAPM_PIN_SWITCH("Speakers"),
+	SOC_DAPM_PIN_SWITCH("Headset Mic"),
+	SOC_DAPM_PIN_SWITCH("Int Mic"),
+};
+
+static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+	unsigned int mclk;
+	int ret;
+
+	/* max98357a supports these sample rates */
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 48000:
+	case 96000:
+		mclk = params_rate(params) * SOUND_FS;
+		break;
+	default:
+		dev_err(rtd->card->dev, "%s() doesn't support this sample rate: %d\n",
+				__func__, params_rate(params));
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
+	if (ret) {
+		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
+				__func__, mclk, ret);
+		return ret;
+	}
+
+	snd_soc_dapm_disable_pin(dapm, "Headphones");
+	snd_soc_dapm_enable_pin(dapm, "Speakers");
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	unsigned int mclk;
+	int ret;
+
+	mclk = params_rate(params) * SOUND_FS;
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+				     SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,
+				     mclk, SND_SOC_CLOCK_IN);
+	if (ret) {
+		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
+				__func__, params_rate(params) * 512, ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
+			     struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	struct snd_soc_dai *codec_dai = rtd->codec_dai;
+	struct snd_soc_dapm_context *dapm = &rtd->card->dapm;
+	int mclk, ret;
+
+	/* in bypass mode, the mclk has to be one of the frequencies below */
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 24000:
+	case 32000:
+	case 48000:
+	case 64000:
+	case 96000:
+		mclk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+	case 88200:
+		mclk = 11289600;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
+				     SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
+				     SND_SOC_CLOCK_IN);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
+	if (ret < 0) {
+		dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);
+		return ret;
+	}
+
+	snd_soc_dapm_disable_pin(dapm, "Speakers");
+	snd_soc_dapm_enable_pin(dapm, "Headphones");
+	snd_soc_dapm_sync(dapm);
+
+	return 0;
+}
+
+static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_codec *codec = rtd->codec_dais[0]->codec;
+	int ret;
+
+	/* Enable Headset and 4 Buttons Jack detection */
+	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
+				    SND_JACK_HEADSET |
+				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
+				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
+				    &rockchip_sound_jack, NULL, 0);
+
+	if (ret) {
+		dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);
+		return ret;
+	}
+
+	da7219_aad_jack_det(codec, &rockchip_sound_jack);
+
+	return 0;
+}
+
+static struct snd_soc_ops rockchip_sound_max98357a_ops = {
+	.hw_params = rockchip_sound_max98357a_hw_params,
+};
+
+static struct snd_soc_ops rockchip_sound_rt5514_ops = {
+	.hw_params = rockchip_sound_rt5514_hw_params,
+};
+
+static struct snd_soc_ops rockchip_sound_da7219_ops = {
+	.hw_params = rockchip_sound_da7219_hw_params,
+};
+
+enum {
+	DAILINK_MAX98357A,
+	DAILINK_RT5514,
+	DAILINK_DA7219,
+};
+
+static struct snd_soc_dai_link rockchip_dailinks[] = {
+	[DAILINK_MAX98357A] = {
+		.name = "MAX98357A",
+		.stream_name = "MAX98357A PCM",
+		.codec_dai_name = "HiFi",
+		.ops = &rockchip_sound_max98357a_ops,
+		/* set max98357a as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+	[DAILINK_RT5514] = {
+		.name = "RT5514",
+		.stream_name = "RT5514 PCM",
+		.codec_dai_name = "rt5514-aif1",
+		.ops = &rockchip_sound_rt5514_ops,
+		/* set rt5514 as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+	[DAILINK_DA7219] = {
+		.name = "DA7219",
+		.stream_name = "DA7219 PCM",
+		.codec_dai_name = "da7219-hifi",
+		.init = rockchip_sound_da7219_init,
+		.ops = &rockchip_sound_da7219_ops,
+		/* set da7219 as slave */
+		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+			SND_SOC_DAIFMT_CBS_CFS,
+	},
+};
+
+static struct snd_soc_card rockchip_sound_card = {
+	.name = "rk3399-max98357a-rt5514-da7219",
+	.owner = THIS_MODULE,
+	.dai_link = rockchip_dailinks,
+	.num_links =  ARRAY_SIZE(rockchip_dailinks),
+	.dapm_widgets = rockchip_dapm_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
+	.dapm_routes = rockchip_dapm_routes,
+	.num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
+	.controls = rockchip_controls,
+	.num_controls = ARRAY_SIZE(rockchip_controls),
+};
+
+static int rockchip_sound_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &rockchip_sound_card;
+	struct device_node *cpu_node;
+	int i, ret;
+
+	for (i = 0; i < card->num_links; i++) {
+		cpu_node = of_parse_phandle(pdev->dev.of_node,
+					 "rockchip,cpu", i);
+		if (!cpu_node) {
+			dev_err(&pdev->dev, "Property[%d] 'rockchip,cpu' missing or invalid\n", i);
+			return -EINVAL;
+		}
+
+		rockchip_dailinks[i].platform_of_node = cpu_node;
+		rockchip_dailinks[i].cpu_of_node = cpu_node;
+
+		rockchip_dailinks[i].codec_of_node =
+			of_parse_phandle(pdev->dev.of_node, "rockchip,codec", i);
+		if (!rockchip_dailinks[i].codec_of_node) {
+			dev_err(&pdev->dev,
+				"Property[%d] 'rockchip,codec' missing or invalid\n", i);
+			return -EINVAL;
+		}
+	}
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+
+	ret = devm_snd_soc_register_card(&pdev->dev, card);
+	if (ret)
+		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
+			__func__, ret);
+
+	return ret;
+}
+
+static const struct of_device_id rockchip_sound_of_match[] = {
+	{ .compatible = "rockchip,rk3399-max98357a-rt5514-da7219", },
+	{},
+};
+
+static struct platform_driver rockchip_sound_driver = {
+	.probe = rockchip_sound_probe,
+	.driver = {
+		.name = DRV_NAME,
+		.of_match_table = rockchip_sound_of_match,
+#ifdef CONFIG_PM
+		.pm = &snd_soc_pm_ops,
+#endif
+	},
+};
+
+module_platform_driver(rockchip_sound_driver);
+
+MODULE_AUTHOR("Xing Zheng <zhengxing at rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);
-- 
1.7.9.5




From zhengxing at rock-chips.com  Thu May 26 06:49:08 2016
From: zhengxing at rock-chips.com (Xing Zheng)
Date: Thu, 26 May 2016 21:49:08 +0800
Subject: [PATCH] clk: rockchip: fix cclk error handing
Message-ID: <1464270549-12713-1-git-send-email-zhengxing@rock-chips.com>

It maybe due to a copy-paste error the error handing should be
cclk not clk.

Reported-by: Lin Huang <lin.huang at rock-chips.com>
Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>
---

 drivers/clk/rockchip/clk-cpu.c |    4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/clk/rockchip/clk-cpu.c b/drivers/clk/rockchip/clk-cpu.c
index 4bb130c..05b3d73 100644
--- a/drivers/clk/rockchip/clk-cpu.c
+++ b/drivers/clk/rockchip/clk-cpu.c
@@ -321,9 +321,9 @@ struct clk *rockchip_clk_register_cpuclk(const char *name,
 	}
 
 	cclk = clk_register(NULL, &cpuclk->hw);
-	if (IS_ERR(clk)) {
+	if (IS_ERR(cclk)) {
 		pr_err("%s: could not register cpuclk %s\n", __func__,	name);
-		ret = PTR_ERR(clk);
+		ret = PTR_ERR(cclk);
 		goto free_rate_table;
 	}
 
-- 
1.7.9.5




From rajatja at google.com  Thu May 26 12:00:31 2016
From: rajatja at google.com (Rajat Jain)
Date: Thu, 26 May 2016 12:00:31 -0700
Subject: [2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <1464289231-12325-1-git-send-email-rajatja@google.com>

> RK3399 has a PCIe controller which can be used as Root Complex.
> This driver supports a PCIe controller as Root Complex mode.

1 general feedback I have is that there are a lot of magic constants.
I'd appreciate if they could be converted into macros for easy readability.

> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
> 
>  drivers/pci/host/Kconfig         |   12 +
>  drivers/pci/host/Makefile        |    1 +
>  drivers/pci/host/pcie-rockchip.c | 1181 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1194 insertions(+)
>  create mode 100644 drivers/pci/host/pcie-rockchip.c
> 
> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
> index 8e4f038..76447a8 100644
> --- a/drivers/pci/host/Kconfig
> +++ b/drivers/pci/host/Kconfig
> @@ -245,4 +245,16 @@ config PCIE_ARMADA_8K
>  	  Designware hardware and therefore the driver re-uses the
>  	  Designware core functions to implement the driver.
>  
> +config PCIE_ROCKCHIP
> +	bool "Rockchip PCIe controller"
> +	depends on ARM64 && ARCH_ROCKCHIP
> +	depends on OF
> +	select MFD_SYSCON
> +	select PCI_MSI
> +	select PCI_MSI_IRQ_DOMAIN
> +	help
> +	  Say Y here if you want internal PCI support on Rockchip SoC.
> +	  There are 1 internal PCIe port available to support GEN2 with
> +	  4 slots.
> +
>  endmenu
> diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
> index a6f85e3..fb3871e 100644
> --- a/drivers/pci/host/Makefile
> +++ b/drivers/pci/host/Makefile
> @@ -29,3 +29,4 @@ obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
>  obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
>  obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
>  obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
> +obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
> diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
> new file mode 100644
> index 0000000..4063fd3
> --- /dev/null
> +++ b/drivers/pci/host/pcie-rockchip.c
> @@ -0,0 +1,1181 @@
> +/*
> + * Rockchip AXI PCIe host controller driver
> + *
> + * Copyright (c) 2016 Rockchip, Inc.
> + *
> + * Author: Shawn Lin <shawn.lin at rock-chips.com>
> + *         Wenrui Li <wenrui.li at rock-chips.com>
> + * Bits taken from Synopsys Designware Host controller driver and
> + * ARM PCI Host generic driver.
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/msi.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_pci.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_irq.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +#include <linux/regmap.h>
> +
> +#define REF_CLK_100MHZ			(100 * 1000 * 1000)
> +#define PCIE_CLIENT_BASE		0x0
> +#define PCIE_RC_CONFIG_BASE		0xa00000
> +#define PCIE_CORE_CTRL_MGMT_BASE	0x900000
> +#define PCIE_CORE_AXI_CONF_BASE		0xc00000
> +#define PCIE_CORE_AXI_INBOUND_BASE	0xc00800
> +
> +#define PCIE_CLIENT_BASIC_STATUS0	0x44
> +#define PCIE_CLIENT_BASIC_STATUS1	0x48
> +#define PCIE_CLIENT_INT_MASK		0x4c
> +#define PCIE_CLIENT_INT_STATUS		0x50
> +#define PCIE_CORE_INT_MASK		0x900210
> +#define PCIE_CORE_INT_STATUS		0x90020c
> +
> +/** Size of one AXI Region (not Region 0) */
> +#define	AXI_REGION_SIZE			(0x1 << 20)
> +/** Overall size of AXI area */
> +#define	AXI_OVERALL_SIZE		(64 * (0x1 << 20))

Not used?

> +/** Size of Region 0, equal to sum of sizes of other regions */
> +#define	AXI_REGION_0_SIZE		(32 * (0x1 << 20))
> +#define OB_REG_SIZE_SHIFT		5
> +#define IB_ROOT_PORT_REG_SIZE_SHIFT	3
> +
> +#define AXI_WRAPPER_IO_WRITE		0x6
> +#define AXI_WRAPPER_MEM_WRITE		0x2
> +#define MAX_AXI_IB_ROOTPORT_REGION_NUM	3
> +#define	MIN_AXI_ADDR_BITS_PASSED	8
> +
> +#define ROCKCHIP_PCIE_RPIFR1_INTR_MASK	GENMASK(8, 5)
> +#define ROCKCHIP_PCIE_RPIFR1_INTR_SHIFT	5
> +#define CLIENT_INTERRUPTS \
> +		(LOC_INT | INTA | INTB | INTC | INTD |\
> +		 CORR_ERR | NFATAL_ERR | FATAL_ERR | DPA_INT | \
> +		 HOT_RESET | MSG_DONE | LEGACY_DONE)
> +#define CORE_INTERRUPTS	\
> +		(PRFPE | CRFPE | RRPE | CRFO | RT | RTR | \
> +		 PE | MTR | UCR | FCE | CT | UTC | MMVC)
> +#define PWR_STCG			BIT(0)
> +#define HOT_PLUG			BIT(1)
> +#define PHY_INT				BIT(2)
> +#define UDMA_INT			BIT(3)
> +#define LOC_INT				BIT(4)
> +#define INTA				BIT(5)
> +#define INTB				BIT(6)
> +#define INTC				BIT(7)
> +#define INTD				BIT(8)
> +#define CORR_ERR			BIT(9)
> +#define NFATAL_ERR			BIT(10)
> +#define FATAL_ERR			BIT(11)
> +#define DPA_INT				BIT(12)
> +#define HOT_RESET			BIT(13)
> +#define MSG_DONE			BIT(14)
> +#define LEGACY_DONE			BIT(15)
> +#define PRFPE				BIT(0)
> +#define CRFPE				BIT(1)
> +#define RRPE				BIT(2)
> +#define PRFO				BIT(3)
> +#define CRFO				BIT(4)
> +#define RT				BIT(5)
> +#define RTR				BIT(6)
> +#define PE				BIT(7)
> +#define MTR				BIT(8)
> +#define UCR				BIT(9)
> +#define FCE				BIT(10)
> +#define CT				BIT(11)
> +#define UTC				BIT(18)
> +#define MMVC				BIT(19)
> +
> +#define PCIE_ECAM_BUS(x)		(((x) & 0xFF) << 20)
> +#define PCIE_ECAM_DEV(x)		(((x) & 0x1F) << 15)
> +#define PCIE_ECAM_FUNC(x)		(((x) & 0x7) << 12)
> +#define PCIE_ECAM_REG(x)		(((x) & 0xFFF) << 0)
> +#define PCIE_ECAM_ADDR(bus, dev, func, reg) \
> +	  (PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \
> +	   PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg))
> +
> +#define RC_REGION_0_ADDR_TRANS_H	0x00000000
> +#define RC_REGION_0_ADDR_TRANS_L	0x00000000
> +#define RC_REGION_0_PASS_BITS		(25 - 1)
> +#define RC_REGION_1_ADDR_TRANS_H	0x00000000
> +#define RC_REGION_1_ADDR_TRANS_L	0x00400000
> +#define RC_REGION_1_PASS_BITS		(20 - 1)
> +#define MAX_AXI_WRAPPER_REGION_NUM	33
> +#define PCIE_CLIENT_CONF_ENABLE		BIT(0)
> +#define PCIE_CLIENT_CONF_LANE_NUM(x)	((x / 2) << 4)
> +#define PCIE_CLIENT_MODE_RC		BIT(6)
> +#define PCIE_CLIENT_GEN_SEL_2		BIT(7)
> +#define PCIE_CLIENT_GEN_SEL_1		0x0
> +
> +struct rockchip_pcie_port {
> +	void __iomem *reg_base;
> +	void __iomem *apb_base;
> +	struct regmap *grf;
> +	unsigned int pcie_conf;
> +	unsigned int pcie_status;
> +	unsigned int pcie_laneoff;
> +	struct reset_control *phy_rst;
> +	struct reset_control *core_rst;
> +	struct reset_control *mgmt_rst;
> +	struct reset_control *mgmt_sticky_rst;
> +	struct reset_control *pipe_rst;
> +	struct clk *aclk_pcie;
> +	struct clk *aclk_perf_pcie;
> +	struct clk *hclk_pcie;
> +	struct clk *clk_pciephy_ref;
> +	struct gpio_desc *ep_gpio;
> +	u32 lanes;
> +	resource_size_t		io_base;
> +	struct resource		*cfg;
> +	struct resource		*io;
> +	struct resource		*mem;

Nit: It seems to me that these resource fields (cfg/io/mem) aren't really
used, except for assignment and as temporary variables, so possibly
can be get rid of, (unless you intend to use them in later patches, if any)

> +	struct resource		*busn;
> +	phys_addr_t		io_bus_addr;
> +	u32			io_size;
> +	phys_addr_t		mem_bus_addr;
> +	u32			mem_size;
> +	u8	root_bus_nr;
> +	int irq;
> +	struct msi_controller *msi;
> +
> +	struct device *dev;
> +	struct irq_domain *irq_domain;
> +};
> +
> +static inline u32 pcie_read(struct rockchip_pcie_port *port, u32 reg)
> +{
> +	return readl(port->apb_base + reg);
> +}
> +
> +static inline void pcie_write(struct rockchip_pcie_port *port,
> +			      u32 val, u32 reg)
> +{
> +	writel(val, port->apb_base + reg);
> +}
> +
> +static inline void pcie_pb_wr_cfg(struct rockchip_pcie_port *port,
> +				  u32 addr, u32 data)
> +{
> +	regmap_write(port->grf, port->pcie_conf,
> +		     (0x3ff << 17) | (data << 7) | (addr << 1));
> +	udelay(1);
> +	regmap_write(port->grf, port->pcie_conf,
> +		     (0x1 << 16) | (0x1 << 0));
> +	udelay(1);
> +	regmap_write(port->grf, port->pcie_conf,
> +		     (0x1 << 16) | (0x0 << 0));
> +}
> +
> +static inline u32 pcie_pb_rd_cfg(struct rockchip_pcie_port *port,
> +				 u32 addr)
> +{
> +	u32 val;
> +
> +	regmap_write(port->grf, port->pcie_conf,
> +		     (0x3ff << 17) | (addr << 1));

Taking cue from pcie_pb_wr_cfg(), I'm wondering if there is any
delay required here?

> +	regmap_read(port->grf, port->pcie_status, &val);
> +	return val;
> +}
> +
> +static int rockchip_pcie_valid_config(struct rockchip_pcie_port *pp,
> +				      struct pci_bus *bus, int dev)
> +{
> +	/* access only one slot on each root port */
> +	if (bus->number == pp->root_bus_nr && dev > 0)
> +		return 0;
> +
> +	/*
> +	 * do not read more than one device on the bus directly attached
> +	 * to RC's (Virtual Bridge's) DS side.
> +	 */
> +	if (bus->primary == pp->root_bus_nr && dev > 0)
> +		return 0;
> +
> +	return 1;
> +}
> +
> +static int rockchip_pcie_rd_own_conf(struct rockchip_pcie_port *pp,
> +				     int where, int size,
> +				     u32 *val)
> +{
> +	void __iomem *addr = pp->apb_base + PCIE_RC_CONFIG_BASE + where;
> +
> +	if ((uintptr_t)addr & (size - 1)) {

Use IS_ALIGNED()?

> +		*val = 0;
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +	}
> +
> +	if (size == 4) {
> +		*val = readl(addr);
> +	} else if (size == 2) {
> +		*val = readw(addr);
> +	} else if (size == 1) {
> +		*val = readb(addr);
> +	} else {
> +		*val = 0;
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +	}
> +	return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static int rockchip_pcie_wr_own_conf(struct rockchip_pcie_port *pp,
> +				     int where, int size, u32 val)
> +{
> +	u32 tmp;
> +	int offset;
> +
> +	offset = (where & (~0x3));
> +	tmp = readl(pp->apb_base + PCIE_RC_CONFIG_BASE + offset);
> +	if (size == 4) {
> +		writel(val, pp->apb_base + PCIE_RC_CONFIG_BASE + where);
> +	} else if (size == 2) {
> +		if (where & 0x2)
> +			tmp = ((tmp & 0xffff) | (val << 16));
> +		else
> +			tmp = ((tmp & 0xffff0000) | val);
> +
> +		writel(tmp, pp->apb_base + PCIE_RC_CONFIG_BASE + offset);
> +	} else if (size == 1) {
> +		if ((where & 0x3) == 0)
> +			tmp = ((tmp & (~0xff)) | val);
> +		else if ((where & 0x3) == 1)
> +			tmp = ((tmp & (~0xff00)) | (val << 8));
> +		else if ((where & 0x3) == 2)
> +			tmp = ((tmp & (~0xff0000)) | (val << 16));
> +		else if ((where & 0x3) == 3)
> +			tmp = ((tmp & (~0xff000000)) | (val << 24));
> +
> +		writel(tmp, pp->apb_base + PCIE_RC_CONFIG_BASE + offset);

Why not register sized writes instead of writels?

> +	} else {
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +	}
> +	return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static int rockchip_pcie_rd_other_conf(struct rockchip_pcie_port *pp,
> +				       struct pci_bus *bus, u32 devfn,
> +				       int where, int size, u32 *val)
> +{
> +	u32 busdev;
> +
> +	busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
> +				PCI_FUNC(devfn), where);
> +
> +	if (busdev & (size - 1)) {

Use IS_ALIGNED() for here and the other occurences in
above and below functions.

> +		*val = 0;
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +	}
> +
> +	if (size == 4) {
> +		*val = readl(pp->reg_base + busdev);
> +	} else if (size == 2) {
> +		*val = readw(pp->reg_base + busdev);
> +	} else if (size == 1) {
> +		*val = readb(pp->reg_base + busdev);
> +	} else {
> +		*val = 0;
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +	}
> +	return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static int rockchip_pcie_wr_other_conf(struct rockchip_pcie_port *pp,
> +				       struct pci_bus *bus, u32 devfn,
> +				       int where, int size, u32 val)
> +{
> +	u32 busdev;
> +
> +	busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
> +				PCI_FUNC(devfn), where);
> +	if (busdev & (size - 1))
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +
> +	if (size == 4)
> +		writel(val, pp->reg_base + busdev);
> +	else if (size == 2)
> +		writew(val, pp->reg_base + busdev);
> +	else if (size == 1)
> +		writeb(val, pp->reg_base + busdev);
> +	else
> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> +
> +	return PCIBIOS_SUCCESSFUL;
> +}
> +
> +static int rockchip_pcie_rd_conf(struct pci_bus *bus, u32 devfn, int where,
> +				 int size, u32 *val)
> +{
> +	struct rockchip_pcie_port *pp = bus->sysdata;
> +	int ret;
> +
> +	if (rockchip_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0) {
> +		*val = 0xffffffff;
> +		return PCIBIOS_DEVICE_NOT_FOUND;
> +	}
> +
> +	if (bus->number != pp->root_bus_nr)
> +		ret = rockchip_pcie_rd_other_conf(pp, bus, devfn,
> +						  where, size, val);
> +	else
> +		ret = rockchip_pcie_rd_own_conf(pp, where, size, val);
> +
> +	return ret;
> +}
> +
> +static int rockchip_pcie_wr_conf(struct pci_bus *bus, u32 devfn,
> +				 int where, int size, u32 val)
> +{
> +	struct rockchip_pcie_port *pp = bus->sysdata;
> +	int ret;
> +
> +	if (rockchip_pcie_valid_config(pp, bus, PCI_SLOT(devfn)) == 0)
> +		return PCIBIOS_DEVICE_NOT_FOUND;
> +
> +	if (bus->number != pp->root_bus_nr)
> +		ret = rockchip_pcie_wr_other_conf(pp, bus, devfn,
> +						  where, size, val);
> +	else
> +		ret = rockchip_pcie_wr_own_conf(pp, where, size, val);
> +
> +	return ret;
> +}
> +
> +static struct pci_ops rockchip_pcie_ops = {
> +	.read = rockchip_pcie_rd_conf,
> +	.write = rockchip_pcie_wr_conf,
> +};
> +
> +/**
> + * rockchip_pcie_init_port - Initialize hardware
> + * @port: PCIe port information
> + */
> +static int rockchip_pcie_init_port(struct rockchip_pcie_port *port)
> +{
> +	int err;
> +	u32 status;
> +	unsigned long timeout = jiffies + msecs_to_jiffies(1000);

The way you have currently implemented, would mean that you have set
the cumulative timeout of 1000 msec for all the operations. So if PLL
takes 990 msec to lock, there is only 10 msec for other steps. It may
be better to have individual timeouts I think since you'd know from
HW docs how much should the time out should be?

> +
> +	gpiod_set_value(port->ep_gpio, 0);
> +
> +	/* Make sure PCIe relate block is in reset state */
> +	err = reset_control_assert(port->phy_rst);
> +	if (err) {
> +		dev_err(port->dev, "assert phy_rst err %d\n", err);
> +		return err;
> +	}
> +	err = reset_control_assert(port->core_rst);
> +	if (err) {
> +		dev_err(port->dev, "assert core_rst err %d\n", err);
> +		return err;
> +	}
> +	err = reset_control_assert(port->mgmt_rst);
> +	if (err) {
> +		dev_err(port->dev, "assert mgmt_rst err %d\n", err);
> +		return err;
> +	}
> +	err = reset_control_assert(port->mgmt_sticky_rst);
> +	if (err) {
> +		dev_err(port->dev, "assert mgmt_sticky_rst err %d\n", err);
> +		return err;
> +	}
> +	err = reset_control_assert(port->pipe_rst);
> +	if (err) {
> +		dev_err(port->dev, "assert pipe_rst err %d\n", err);
> +		return err;
> +	}
> +
> +	pcie_write(port, (0xf << 20) | (0x1 << 16) | PCIE_CLIENT_GEN_SEL_2 |
> +			  (0x1 << 19) | (0x1 << 3) |
> +			  PCIE_CLIENT_MODE_RC |
> +			  PCIE_CLIENT_CONF_LANE_NUM(port->lanes) |
> +			  PCIE_CLIENT_CONF_ENABLE, PCIE_CLIENT_BASE);
> +
> +	err = reset_control_deassert(port->phy_rst);
> +	if (err) {
> +		dev_err(port->dev, "deassert phy_rst err %d\n", err);
> +		return err;
> +	}
> +	regmap_write(port->grf, port->pcie_conf,
> +		     (0x3f << 17) | (0x10 << 1));
> +	err = -EINVAL;
> +	while (time_before(jiffies, timeout)) {
> +		regmap_read(port->grf, port->pcie_status, &status);
> +		if ((status & (1 << 9))) {
> +			dev_info(port->dev, "pll locked!\n");
> +			err = 0;
> +			break;
> +		}
> +	}
> +	if (err) {
> +		dev_err(port->dev, "pll lock timeout!\n");
> +		return err;
> +	}
> +	pcie_pb_wr_cfg(port, 0x10, 0x8);
> +	pcie_pb_wr_cfg(port, 0x12, 0x8);
> +
> +	err = -ETIMEDOUT;
> +	while (time_before(jiffies, timeout)) {
> +		regmap_read(port->grf, port->pcie_status, &status);
> +		if (!(status & (1 << 10))) {
> +			dev_info(port->dev, "pll output enable done!\n");
> +			err = 0;
> +			break;
> +		}
> +	}
> +
> +	if (err) {
> +		dev_err(port->dev, "pll output enable timeout!\n");
> +		return err;
> +	}
> +
> +	regmap_write(port->grf, port->pcie_conf,
> +		     (0x3f << 17) | (0x10 << 1));
> +	err = -EINVAL;
> +	while (time_before(jiffies, timeout)) {
> +		regmap_read(port->grf, port->pcie_status, &status);
> +		if ((status & (1 << 9))) {
> +			dev_info(port->dev, "pll relocked!\n");
> +			err = 0;
> +			break;
> +		}
> +	}
> +	if (err) {
> +		dev_err(port->dev, "pll relock timeout!\n");
> +		return err;
> +	}

There's a bunch of these "regmap_write, loop waiting for a bit, error check"(s)
May be have an inline function for it?

> +
> +	err = reset_control_deassert(port->core_rst);
> +	if (err) {
> +		dev_err(port->dev, "deassert core_rst err %d\n", err);
> +		return err;
> +	}
> +	err = reset_control_deassert(port->mgmt_rst);
> +	if (err) {
> +		dev_err(port->dev, "deassert mgmt_rst err %d\n", err);
> +		return err;
> +	}
> +	err = reset_control_deassert(port->mgmt_sticky_rst);
> +	if (err) {
> +		dev_err(port->dev, "deassert mgmt_sticky_rst err %d\n", err);
> +		return err;
> +	}
> +	err = reset_control_deassert(port->pipe_rst);
> +	if (err) {
> +		dev_err(port->dev, "deassert pipe_rst err %d\n", err);
> +		return err;
> +	}
> +
> +	pcie_write(port, 1 << 17 | 1 << 1, PCIE_CLIENT_BASE);
> +
> +	gpiod_set_value(port->ep_gpio, 1);
> +	err = -ETIMEDOUT;
> +	while (time_before(jiffies, timeout)) {
> +		status = pcie_read(port, PCIE_CLIENT_BASIC_STATUS1);
> +		if (((status >> 20) & 0x3) == 0x3) {
> +			dev_info(port->dev, "pcie link training gen1 pass!\n");
> +			err = 0;
> +			break;
> +		}
> +	}
> +	if (err) {
> +		dev_err(port->dev, "pcie link training gen1 timeout!\n");
> +		return err;
> +	}
> +
> +	status = pcie_read(port, 0x9000d0);
> +	status |= 0x20;
> +	pcie_write(port, status, 0x9000d0);
> +	err = -ETIMEDOUT;
> +	while (time_before(jiffies, timeout)) {
> +		status = pcie_read(port, PCIE_CORE_CTRL_MGMT_BASE);
> +		if (((status >> 3) & 0x3) == 0x1) {
> +			dev_info(port->dev, "pcie link training gen2 pass!\n");
> +			err = 0;
> +			break;
> +		}
> +	}
> +	if (err)
> +		dev_dbg(port->dev, "pcie link training gen2 timeout, force to gen1!\n");
> +
> +	if (((status >> 3) & 0x3) == 0x0)
> +		dev_info(port->dev, "pcie link 2.5!\n");
> +	if (((status >> 3) & 0x3) == 0x1)
> +		dev_info(port->dev, "pcie link 5.0!\n");
> +
> +	status = pcie_read(port, PCIE_CORE_CTRL_MGMT_BASE);
> +	status =  0x1 << ((status >> 1) & 0x3);
> +	dev_info(port->dev, "current link width is x%d\n", status);
> +
> +	status = pcie_pb_rd_cfg(port, 0x30);
> +	if (!((status >> 11) & 0x1))
> +		dev_dbg(port->dev, "lane A is used\n");
> +	else
> +		regmap_write(port->grf, port->pcie_laneoff,
> +			     (0x1 << 19) | (0x1 << 3));
> +
> +	status = pcie_pb_rd_cfg(port, 0x31);
> +	if (!((status >> 11) & 0x1))
> +		dev_dbg(port->dev, "lane B is used\n");
> +	else
> +		regmap_write(port->grf, port->pcie_laneoff,
> +			     (0x2 << 19) | (0x2 << 3));
> +
> +	status = pcie_pb_rd_cfg(port, 0x32);
> +	if (!((status >> 11) & 0x1))
> +		dev_dbg(port->dev, "lane C is used\n");
> +	else
> +		regmap_write(port->grf, port->pcie_laneoff,
> +			     (0x4 << 19) | (0x4 << 3));
> +
> +	status = pcie_pb_rd_cfg(port, 0x33);
> +	if (!((status >> 11) & 0x1))
> +		dev_dbg(port->dev, "lane D is used\n");
> +	else
> +		regmap_write(port->grf, port->pcie_laneoff,
> +			     (0x8 << 19) | (0x8 << 3));

Can we have a loop looping over all the lanes instead of this?
Also, you seem to be checking and initializing all lanes instead
of referring to port->lanes?

> +	return 0;
> +}
> +
> +/**
> + * rockchip_pcie_parse_dt - Parse Device tree
> + * @port: PCIe port information
> + *
> + * Return: '0' on success and error value on failure
> + */
> +static int rockchip_pcie_parse_dt(struct rockchip_pcie_port *port)
> +{
> +	struct device *dev = port->dev;
> +	struct device_node *node = dev->of_node;
> +	struct resource regs;
> +	unsigned int pcie_conf;
> +	unsigned int pcie_status;
> +	unsigned int pcie_laneoff;
> +	int err;
> +
> +	err = of_address_to_resource(node, 0, &regs);
> +	if (err) {
> +		dev_err(dev, "missing \"reg\" property\n");

This error message is exactly the same as the one below.
May be say reg0 or reg1?

> +		return err;
> +	}
> +
> +	port->reg_base = devm_ioremap_resource(dev, &regs);
> +	if (IS_ERR(port->reg_base))
> +		return PTR_ERR(port->reg_base);
> +
> +	err = of_address_to_resource(node, 1, &regs);
> +	if (err) {
> +		dev_err(dev, "missing \"reg\" property\n");
> +		return err;
> +	}
> +
> +	port->apb_base = devm_ioremap_resource(dev, &regs);
> +	if (IS_ERR(port->apb_base))
> +		return PTR_ERR(port->apb_base);
> +
> +	port->grf = syscon_regmap_lookup_by_phandle(dev->of_node,
> +						    "rockchip,grf");
> +	if (IS_ERR(port->grf)) {
> +		dev_err(dev, "Missing rockchip,grf property\n");
> +		return PTR_ERR(port->grf);
> +	}
> +
> +	if (of_property_read_u32(node, "pcie-conf", &pcie_conf)) {
> +		dev_err(dev, "missing pcie-conf property in node %s\n",
> +			node->name);
> +		return -EINVAL;
> +	}
> +
> +	port->pcie_conf = pcie_conf;
> +
> +	if (of_property_read_u32(node, "pcie-status", &pcie_status)) {
> +		dev_err(dev, "missing pcie-status property in node %s\n",
> +			node->name);
> +		return -EINVAL;
> +	}
> +
> +	port->pcie_status = pcie_status;
> +
> +	if (of_property_read_u32(node, "pcie-laneoff", &pcie_laneoff)) {
> +		dev_err(dev, "missing pcie-laneoff property in node %s\n",
> +			node->name);
> +		return -EINVAL;
> +	}
> +
> +	port->pcie_laneoff = pcie_laneoff;
> +
> +	port->lanes = 1;
> +	err = of_property_read_u32(node, "num-lanes", &port->lanes);
> +	if (!err && ((port->lanes == 0) ||
> +		     (port->lanes == 3) ||
> +		     (port->lanes > 4))) {
> +		dev_info(dev, "invalid num-lanes, default use one lane\n");
> +		port->lanes = 1;
> +	}
> +
> +	port->phy_rst = devm_reset_control_get(dev, "phy-rst");
> +	if (IS_ERR(port->phy_rst)) {
> +		if (PTR_ERR(port->phy_rst) != -EPROBE_DEFER)
> +			dev_err(dev, "missing phy-rst property in node %s\n",
> +				node->name);
> +		err = PTR_ERR(port->phy_rst);
> +		goto err_aclk_pcie;
> +	}
> +
> +	port->core_rst = devm_reset_control_get(dev, "core-rst");
> +	if (IS_ERR(port->core_rst)) {
> +		if (PTR_ERR(port->core_rst) != -EPROBE_DEFER)
> +			dev_err(dev, "missing core-rst property in node %s\n",
> +				node->name);
> +		err = PTR_ERR(port->core_rst);
> +		goto err_aclk_pcie;
> +	}
> +
> +	port->mgmt_rst = devm_reset_control_get(dev, "mgmt-rst");
> +	if (IS_ERR(port->mgmt_rst)) {
> +		if (PTR_ERR(port->mgmt_rst) != -EPROBE_DEFER)
> +			dev_err(dev, "missing mgmt-rst property in node %s\n",
> +				node->name);
> +		err = PTR_ERR(port->mgmt_rst);
> +		goto err_aclk_pcie;
> +	}
> +
> +	port->mgmt_sticky_rst = devm_reset_control_get(dev, "mgmt-sticky-rst");
> +	if (IS_ERR(port->mgmt_sticky_rst)) {
> +		if (PTR_ERR(port->mgmt_sticky_rst) != -EPROBE_DEFER)
> +			dev_err(dev, "missing mgmt-sticky-rst property in node %s\n",
> +				node->name);
> +		err = PTR_ERR(port->mgmt_sticky_rst);
> +		goto err_aclk_pcie;
> +	}
> +
> +	port->pipe_rst = devm_reset_control_get(dev, "pipe-rst");
> +	if (IS_ERR(port->pipe_rst)) {
> +		if (PTR_ERR(port->pipe_rst) != -EPROBE_DEFER)
> +			dev_err(dev, "missing pipe-rst property in node %s\n",
> +				node->name);
> +		err = PTR_ERR(port->pipe_rst);
> +		goto err_aclk_pcie;
> +	}
> +
> +	port->ep_gpio = gpiod_get(dev, "ep", GPIOD_OUT_HIGH);
> +	if (IS_ERR(port->ep_gpio)) {
> +		dev_err(dev, "missing ep-gpios property in node %s\n",
> +			node->name);
> +		return PTR_ERR(port->ep_gpio);
> +	}
> +
> +	port->aclk_pcie = devm_clk_get(dev, "aclk_pcie");
> +	if (IS_ERR(port->aclk_pcie)) {
> +		dev_err(dev, "aclk_pcie clock not found.\n");
> +		return PTR_ERR(port->aclk_pcie);
> +	}
> +
> +	port->aclk_perf_pcie = devm_clk_get(dev, "aclk_perf_pcie");
> +	if (IS_ERR(port->aclk_perf_pcie)) {
> +		dev_err(dev, "aclk_perf_pcie clock not found.\n");
> +		return PTR_ERR(port->aclk_perf_pcie);
> +	}
> +
> +	port->hclk_pcie = devm_clk_get(dev, "hclk_pcie");
> +	if (IS_ERR(port->hclk_pcie)) {
> +		dev_err(dev, "hclk_pcie clock not found.\n");
> +		return PTR_ERR(port->hclk_pcie);
> +	}
> +
> +	port->clk_pciephy_ref = devm_clk_get(dev, "clk_pciephy_ref");
> +	if (IS_ERR(port->clk_pciephy_ref)) {
> +		dev_err(dev, "clk_pciephy_ref clock not found.\n");
> +		return PTR_ERR(port->clk_pciephy_ref);
> +	}
> +
> +	err = clk_prepare_enable(port->aclk_pcie);
> +	if (err) {
> +		dev_err(dev, "Unable to enable aclk_pcie clock.\n");
> +		goto err_aclk_pcie;
> +	}
> +
> +	err = clk_prepare_enable(port->aclk_perf_pcie);
> +	if (err) {
> +		dev_err(dev, "Unable to enable aclk_perf_pcie clock.\n");
> +		goto err_aclk_perf_pcie;
> +	}
> +
> +	err = clk_prepare_enable(port->hclk_pcie);
> +	if (err) {
> +		dev_err(dev, "Unable to enable hclk_pcie clock.\n");
> +		goto err_hclk_pcie;
> +	}
> +
> +	err = clk_prepare_enable(port->clk_pciephy_ref);
> +	if (err) {
> +		dev_err(dev, "Unable to enable hclk_pcie clock.\n");
> +		goto err_pciephy_ref;
> +	}

IMHO, the code in rockchip_pcie_parse_dt() is doing much more than
what the function name says i.e. "parsing the dt". May be move the
clk_prepare_enable() calls out (and possibly others).

> +
> +	return 0;
> +
> +err_pciephy_ref:
> +	clk_disable_unprepare(port->hclk_pcie);
> +err_hclk_pcie:
> +	clk_disable_unprepare(port->aclk_perf_pcie);
> +err_aclk_perf_pcie:
> +	clk_disable_unprepare(port->aclk_pcie);
> +err_aclk_pcie:
> +	return err;
> +}
> +
> +static void rockchip_pcie_msi_enable(struct rockchip_pcie_port *pp)
> +{

This function seems to be (only) parsing the dt? If so we can move its
code to parse_dt function?

> +	struct device_node *msi_node;
> +
> +	msi_node = of_parse_phandle(pp->dev->of_node,
> +				    "msi-parent", 0);
> +	if (!msi_node)
> +		return;
> +
> +	pp->msi = of_pci_find_msi_chip_by_node(msi_node);
> +	of_node_put(msi_node);
> +
> +	if (pp->msi)
> +		pp->msi->dev = pp->dev;
> +}
> +
> +static void rockchip_pcie_enable_interrupts(struct rockchip_pcie_port *pp)
> +{
> +	pcie_write(pp, (CLIENT_INTERRUPTS << 16) &
> +		   (~CLIENT_INTERRUPTS), PCIE_CLIENT_INT_MASK);
> +	pcie_write(pp, CORE_INTERRUPTS, PCIE_CORE_INT_MASK);
> +}
> +
> +static int rockchip_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
> +				  irq_hw_number_t hwirq)
> +{
> +	irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
> +	irq_set_chip_data(irq, domain->host_data);
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops intx_domain_ops = {
> +	.map = rockchip_pcie_intx_map,
> +};
> +
> +static int rockchip_pcie_init_irq_domain(struct rockchip_pcie_port *pp)
> +{
> +	struct device *dev = pp->dev;
> +	struct device_node *node = dev->of_node;
> +	struct device_node *pcie_intc_node =  of_get_next_child(node, NULL);
> +
> +	if (!pcie_intc_node) {
> +		dev_err(dev, "No PCIe Intc node found\n");
> +		return PTR_ERR(pcie_intc_node);
> +	}
> +	pp->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
> +					       &intx_domain_ops, pp);
> +	if (!pp->irq_domain) {
> +		dev_err(dev, "Failed to get a INTx IRQ domain\n");
> +		return PTR_ERR(pp->irq_domain);
> +	}
> +
> +	return 0;
> +}
> +
> +static irqreturn_t rockchip_pcie_subsys_irq_handler(int irq, void *arg)
> +{
> +	struct rockchip_pcie_port *pp = arg;
> +	u32 reg;
> +	u32 sub_reg;
> +
> +	reg = pcie_read(pp, PCIE_CLIENT_INT_STATUS);
> +	if (reg & LOC_INT) {
> +		dev_dbg(pp->dev, "local interrupt recived\n");
> +		sub_reg = pcie_read(pp, PCIE_CORE_INT_STATUS);
> +		if (sub_reg & PRFPE)
> +			dev_dbg(pp->dev, "Parity error detected while reading from the PNP Receive FIFO RAM\n");
> +
> +		if (sub_reg & CRFPE)
> +			dev_dbg(pp->dev, "Parity error detected while reading from the Completion Receive FIFO RAM\n");
> +
> +		if (sub_reg & RRPE)
> +			dev_dbg(pp->dev, "Parity error detected while reading from Replay Buffer RAM\n");
> +
> +		if (sub_reg & PRFO)
> +			dev_dbg(pp->dev, "Overflow occurred in the PNP Receive FIFO\n");
> +
> +		if (sub_reg & CRFO)
> +			dev_dbg(pp->dev, "Overflow occurred in the Completion Receive FIFO\n");
> +
> +		if (sub_reg & RT)
> +			dev_dbg(pp->dev, "Replay timer timed out\n");
> +
> +		if (sub_reg & RTR)
> +			dev_dbg(pp->dev, "Replay timer rolled over after 4 transmissions of the same TLP\n");
> +
> +		if (sub_reg & PE)
> +			dev_dbg(pp->dev, "Phy error detected on receive side\n");
> +
> +		if (sub_reg & MTR)
> +			dev_dbg(pp->dev, "Malformed TLP received from the link\n");
> +
> +		if (sub_reg & UCR)
> +			dev_dbg(pp->dev, "Malformed TLP received from the link\n");
> +
> +		if (sub_reg & FCE)
> +			dev_dbg(pp->dev, "An error was observed in the flow control advertisements from the other side\n");
> +
> +		if (sub_reg & CT)
> +			dev_dbg(pp->dev, "A request timed out waiting for completion\n");
> +
> +		if (sub_reg & UTC)
> +			dev_dbg(pp->dev, "Unmapped TC error\n");
> +
> +		if (sub_reg & MMVC)
> +			dev_dbg(pp->dev, "MSI mask register changes\n");
> +
> +		pcie_write(pp, sub_reg, PCIE_CORE_INT_STATUS);
> +	}
> +
> +	pcie_write(pp, reg, PCIE_CLIENT_INT_STATUS);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t rockchip_pcie_client_irq_handler(int irq, void *arg)
> +{
> +	struct rockchip_pcie_port *pp = arg;
> +	u32 reg;
> +
> +	reg = pcie_read(pp, PCIE_CLIENT_INT_STATUS);
> +	if (reg & LEGACY_DONE)
> +		dev_dbg(pp->dev, "legacy done interrupt recived\n");
> +
> +	if (reg & MSG_DONE)
> +		dev_dbg(pp->dev, "message done interrupt recived\n");
> +
> +	if (reg & HOT_RESET)
> +		dev_dbg(pp->dev, "hot reset interrupt recived\n");
> +
> +	if (reg & DPA_INT)
> +		dev_dbg(pp->dev, "dpa interrupt recived\n");
> +
> +	if (reg & FATAL_ERR)
> +		dev_dbg(pp->dev, "fatal error interrupt recived\n");
> +
> +	if (reg & DPA_INT)
> +		dev_dbg(pp->dev, "no fatal error interrupt recived\n");
> +
> +	if (reg & CORR_ERR)
> +		dev_dbg(pp->dev, "correctable error interrupt recived\n");
> +
> +	pcie_write(pp, reg, PCIE_CLIENT_INT_STATUS);

This is a curosity question. You have 3 interrupt handlers, and in all 3 of them
you are checking the same register (PCIE_CLIENT_INT_STATUS) and unconditionally
clearing all the interrupts in that register. So I think if pci-sys and legacy
are raised at the same time, the 1st interrupt handler that gets called may clear
all interrupts and the second may find none to service. This may be OK, I'm wondering
if this is the intention?

> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t rockchip_pcie_legacy_int_handler(int irq, void *arg)
> +{
> +	struct rockchip_pcie_port *pp = arg;
> +	u32 reg;
> +
> +	reg = pcie_read(pp, PCIE_CLIENT_INT_STATUS);
> +	reg = (reg & ROCKCHIP_PCIE_RPIFR1_INTR_MASK) >>
> +	       ROCKCHIP_PCIE_RPIFR1_INTR_SHIFT;
> +	generic_handle_irq(irq_find_mapping(pp->irq_domain, ffs(reg)));
> +
> +	pcie_write(pp, reg, PCIE_CLIENT_INT_STATUS);
> +	return IRQ_HANDLED;
> +}
> +
> +static int rockchip_pcie_prog_ob_atu(struct rockchip_pcie_port *pp,
> +				     int region_no,
> +				     int type, u8 num_pass_bits,
> +				     u32 lower_addr, u32 upper_addr)
> +{
> +	u32 ob_addr_0 = 0;
> +	u32 ob_addr_1 = 0;
> +	u32 ob_desc_0 = 0;
> +	u32 ob_desc_1 = 0;
> +	void __iomem *aw_base;
> +
> +	if (!pp)
> +		return -EINVAL;
> +	if (region_no >= MAX_AXI_WRAPPER_REGION_NUM)
> +		return -EINVAL;
> +	if ((num_pass_bits + 1) < 8)
> +		return -EINVAL;
> +	if (num_pass_bits > 63)
> +		return -EINVAL;
> +	if (region_no == 0) {
> +		if (AXI_REGION_0_SIZE < (2ULL << num_pass_bits))
> +		return -EINVAL;
> +	}
> +	if (region_no != 0) {
> +		if (AXI_REGION_SIZE < (2ULL << num_pass_bits))
> +		return -EINVAL;
> +	}
> +	aw_base = pp->apb_base + PCIE_CORE_AXI_CONF_BASE;
> +	aw_base += (region_no << OB_REG_SIZE_SHIFT);
> +
> +	ob_addr_0 = (ob_addr_0 &
> +		     ~0x0000003fU) | (num_pass_bits &
> +		     0x0000003fU);
> +	ob_addr_0 = (ob_addr_0 &
> +		     ~0xffffff00U) | (lower_addr & 0xffffff00U);
> +	ob_addr_1 = upper_addr;
> +	ob_desc_0 = (1 << 23 | type);
> +
> +	writel(ob_addr_0, aw_base);
> +	writel(ob_addr_1, aw_base + 0x4);
> +	writel(ob_desc_0, aw_base + 0x8);
> +	writel(ob_desc_1, aw_base + 0xc);
> +
> +	return 0;
> +}
> +
> +static int rockchip_pcie_prog_ib_atu(struct rockchip_pcie_port *pp,
> +				     int region_no,
> +				     u8 num_pass_bits,
> +				     u32 lower_addr,
> +				     u32 upper_addr)
> +{
> +	u32 ib_addr_0 = 0;
> +	u32 ib_addr_1 = 0;
> +	void __iomem *aw_base;
> +
> +	if (!pp)
> +		return -EINVAL;
> +	if (region_no > MAX_AXI_IB_ROOTPORT_REGION_NUM)
> +		return -EINVAL;
> +	if ((num_pass_bits + 1) < MIN_AXI_ADDR_BITS_PASSED)
> +		return -EINVAL;
> +	if (num_pass_bits > 63)
> +		return -EINVAL;
> +	aw_base = pp->apb_base + PCIE_CORE_AXI_INBOUND_BASE;
> +	aw_base += (region_no << IB_ROOT_PORT_REG_SIZE_SHIFT);
> +	ib_addr_0 = (ib_addr_0 &
> +		     ~0x0000003fU) | (num_pass_bits &
> +		     0x0000003fU);
> +
> +	ib_addr_0 = (ib_addr_0 & ~0xffffff00U) |
> +		     ((lower_addr << 8) & 0xffffff00U);
> +	ib_addr_1 = upper_addr;
> +	writel(ib_addr_0, aw_base);
> +	writel(ib_addr_1, aw_base + 0x4);
> +
> +	return 0;
> +}
> +
> +static int rockchip_pcie_probe(struct platform_device *pdev)
> +{
> +	struct rockchip_pcie_port *port;
> +	struct device *dev = &pdev->dev;
> +	struct pci_bus *bus, *child;
> +	struct resource_entry *win;
> +	int reg_no;
> +	int err = 0;
> +	int irq;
> +	LIST_HEAD(res);
> +
> +	if (!dev->of_node)
> +		return -ENODEV;
> +
> +	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> +	if (!port)
> +		return -ENOMEM;
> +
> +	irq = platform_get_irq_byname(pdev, "pcie-sys");
> +	if (irq < 0) {
> +		dev_err(dev, "missing pcie_sys IRQ resource\n");
> +		return -EINVAL;
> +	}
> +	err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler,
> +			       IRQF_SHARED, "pcie-sys", port);

I am a little worried because you are installing all the 3
interrupt handlers, passing "port *" as the argument - even
though the struct port is not initialized yet. Specifically the
pointers (port->apb_base) that irq handler would dereference. 
Also, the irq domain is not initialized. May be I'm
just cynical, but if there is an interrupt pending, I'm wondering
if your interrupt handler can get called even before you get a
chance to initialize your struct rockchip_pcie_port *port or irq domain?
If so, it may crash. So may be better to first parse dt and initialize
your structures before registering the interrupt handler(s)?

> +	if (err) {
> +		dev_err(dev, "failed to request pcie subsystem irq\n");
> +		return err;
> +	}
> +
> +	port->irq = platform_get_irq_byname(pdev, "pcie-legacy");
> +	if (port->irq < 0) {
> +		dev_err(dev, "missing pcie_legacy IRQ resource\n");
> +		return -EINVAL;
> +	}
> +	err = devm_request_irq(dev, port->irq,
> +			       rockchip_pcie_legacy_int_handler,
> +			       IRQF_SHARED,
> +			       "pcie-legacy",
> +			       port);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to request pcie-legacy irq\n");
> +		return err;
> +	}
> +
> +	irq = platform_get_irq_byname(pdev, "pcie-client");
> +	if (irq < 0) {
> +		dev_err(dev, "missing pcie-client IRQ resource\n");
> +		return -EINVAL;
> +	}
> +	err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler,
> +			       IRQF_SHARED, "pcie-client", port);
> +	if (err) {
> +		dev_err(dev, "failed to request pcie client irq\n");
> +		return err;
> +	}
> +
> +	port->dev = dev;
> +	err = rockchip_pcie_parse_dt(port);
> +	if (err) {
> +		dev_err(dev, "Parsing DT failed\n");
> +		return err;
> +	}
> +
> +	err = rockchip_pcie_init_port(port);
> +	if (err)
> +		return err;

What about clocks? Do you need to clk_disable_unprepare() them
on this failure or any subsequent failure in probe?

> +
> +	platform_set_drvdata(pdev, port);
> +
> +	rockchip_pcie_enable_interrupts(port);
> +	if (!IS_ENABLED(CONFIG_PCI_MSI)) {
> +		err = rockchip_pcie_init_irq_domain(port);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff,
> +					       &res, &port->io_base);
> +	if (err)
> +		return err;
> +	/* Get the I/O and memory ranges from DT */
> +	resource_list_for_each_entry(win, &res) {
> +		switch (resource_type(win->res)) {
> +		case IORESOURCE_IO:
> +			port->io = win->res;
> +			port->io->name = "I/O";
> +			port->io_size = resource_size(port->io);
> +			port->io_bus_addr = port->io->start - win->offset;
> +			err = pci_remap_iospace(port->io, port->io_base);
> +			if (err) {
> +				dev_warn(port->dev, "error %d: failed to map resource %pR\n",
> +					 err, port->io);
> +				continue;
> +			}
> +			break;
> +		case IORESOURCE_MEM:
> +			port->mem = win->res;
> +			port->mem->name = "MEM";
> +			port->mem_size = resource_size(port->mem);
> +			port->mem_bus_addr = port->mem->start - win->offset;
> +			break;
> +		case 0:
> +			port->cfg = win->res;
> +			break;
> +		case IORESOURCE_BUS:
> +			port->busn = win->res;
> +			break;
> +		default:
> +			continue;
> +		}
> +	}
> +
> +	pcie_write(port, 0x6040000, PCIE_RC_CONFIG_BASE + 0x8);
> +	pcie_write(port, 0x0, PCIE_CORE_CTRL_MGMT_BASE + 0x300);
> +
> +	pcie_write(port, (RC_REGION_0_ADDR_TRANS_L + RC_REGION_0_PASS_BITS),
> +		   PCIE_CORE_AXI_CONF_BASE);
> +	pcie_write(port, RC_REGION_0_ADDR_TRANS_H,
> +		   PCIE_CORE_AXI_CONF_BASE + 0x4);
> +	pcie_write(port, 0x0080000a, PCIE_CORE_AXI_CONF_BASE + 0x8);
> +	pcie_write(port, 0x00000000, PCIE_CORE_AXI_CONF_BASE + 0xc);
> +
> +	for (reg_no = 0; reg_no < (port->mem_size >> 20); reg_no++) {
> +		err = rockchip_pcie_prog_ob_atu(port, reg_no + 1,
> +						AXI_WRAPPER_MEM_WRITE,
> +						20 - 1,
> +						port->mem_bus_addr +
> +							(reg_no << 20),
> +						0);
> +		if (err) {
> +			dev_err(dev, "Program RC outbound atu failed\n");
> +			return err;
> +		}
> +	}
> +
> +	err = rockchip_pcie_prog_ib_atu(port, 2, 32 - 1, 0x0, 0);
> +	if (err) {
> +		dev_err(dev, "Program RC inbound atu failed\n");
> +		return err;
> +	}
> +
> +	rockchip_pcie_msi_enable(port);
> +
> +	port->root_bus_nr = port->busn->start;
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		bus = pci_scan_root_bus_msi(port->dev, port->root_bus_nr,
> +					    &rockchip_pcie_ops, port, &res,
> +					    port->msi);
> +	} else {
> +		bus = pci_scan_root_bus(&pdev->dev, 0,
> +					&rockchip_pcie_ops, port, &res);
> +	}
> +	if (!bus)
> +		return -ENOMEM;
> +
> +	if (!pci_has_flag(PCI_PROBE_ONLY)) {
> +		pci_bus_size_bridges(bus);
> +		pci_bus_assign_resources(bus);
> +		list_for_each_entry(child, &bus->children, node)
> +			pcie_bus_configure_settings(child);
> +	}
> +
> +	pci_bus_add_devices(bus);
> +
> +	return err;
> +}
> +
> +static int rockchip_pcie_remove(struct platform_device *pdev)
> +{
> +	struct rockchip_pcie_port *port = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(port->hclk_pcie);
> +	clk_disable_unprepare(port->aclk_perf_pcie);
> +	clk_disable_unprepare(port->aclk_pcie);
> +	clk_disable_unprepare(port->clk_pciephy_ref);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id rockchip_pcie_of_match[] = {
> +	{ .compatible = "rockchip,rk3399-pcie", },
> +	{}
> +};

Please add a MODULE_DEVICE_TABLE() here.

> +
> +static struct platform_driver rockchip_pcie_driver = {
> +	.driver = {
> +		.name = "rockchip-pcie",
> +		.of_match_table = rockchip_pcie_of_match,
> +		.suppress_bind_attrs = true,
> +	},
> +	.probe = rockchip_pcie_probe,
> +	.remove = rockchip_pcie_remove,
> +};
> +module_platform_driver(rockchip_pcie_driver);
> +
> +MODULE_AUTHOR("Rockchip Inc");
> +MODULE_DESCRIPTION("Rockchip AXI PCIe driver");
> +MODULE_LICENSE("GPL v2");


From heiko at sntech.de  Thu May 26 14:47:39 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Thu, 26 May 2016 23:47:39 +0200
Subject: [PATCH] clk: rockchip: fix cclk error handing
In-Reply-To: <1464270549-12713-1-git-send-email-zhengxing@rock-chips.com>
References: <1464270549-12713-1-git-send-email-zhengxing@rock-chips.com>
Message-ID: <1509769.ko7YVcsoMN@phil>

Am Donnerstag, 26. Mai 2016, 21:49:08 schrieb Xing Zheng:
> It maybe due to a copy-paste error the error handing should be
> cclk not clk.
> 
> Reported-by: Lin Huang <lin.huang at rock-chips.com>
> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>

applied to my clk-fixes branch after adapting the commit message a bit.


Thanks for catching that
Heiko


From heiko at sntech.de  Thu May 26 16:17:27 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 27 May 2016 01:17:27 +0200
Subject: [PATCH] clk: rockchip: add a dummy clock for the watchdog pclk on
 rk3399
In-Reply-To: <1464166316-22480-1-git-send-email-zhengxing@rock-chips.com>
References: <1464166316-22480-1-git-send-email-zhengxing@rock-chips.com>
Message-ID: <7878987.CKGkxk3Y7s@phil>

Am Mittwoch, 25. Mai 2016, 16:51:56 schrieb Xing Zheng:
> Like rk3288, the pclk supplying the watchdog is controlled via the
> SGRF register area. Additionally the SGRF isn't even writable in
> every boot mode.
> 
> But still the clock control is available and in the future someone
> might want to use it. Therefore define a simple clock for the time
> being so that the watchdog driver can read its rate.
> 
> Signed-off-by: Xing Zheng <zhengxing at rock-chips.com>

applied for 4.8

Thanks
Heiko


From jh80.chung at samsung.com  Thu May 26 17:53:18 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Fri, 27 May 2016 09:53:18 +0900
Subject: [RFC PATCH 1/2] mmc: dw_mmc: remove redundant of set_bit and
 clear_bit
In-Reply-To: <1464232063-24841-1-git-send-email-shawn.lin@rock-chips.com>
References: <CGME20160526030828epcas1p16b97a230c35c2599a2b8fcada376c9de@epcas1p1.samsung.com>
 <1464232063-24841-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <57479A7E.3050103@samsung.com>

Hi Shawn,

On 05/26/2016 12:07 PM, Shawn Lin wrote:
> dw_mci_get_cd have already dealed with these for
> both of internal card-detect and gpio card-detect.

s/dealed/dealt

This patch looks good to me. Could you resend the patch? not RFC.

Best Regards,
Jaehoon Chung

> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> 
> ---
> 
>  drivers/mmc/host/dw_mmc.c | 5 +----
>  1 file changed, 1 insertion(+), 4 deletions(-)
> 
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 829a6ee..cb30e91 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -2616,10 +2616,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>  		mmc->max_seg_size = mmc->max_req_size;
>  	}
>  
> -	if (dw_mci_get_cd(mmc))
> -		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
> -	else
> -		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
> +	dw_mci_get_cd(mmc);
>  
>  	ret = mmc_add_host(mmc);
>  	if (ret)
> 



From jh80.chung at samsung.com  Thu May 26 17:53:24 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Fri, 27 May 2016 09:53:24 +0900
Subject: [RFC PATCH 2/2] mmc: dw_mmc: check card present before starting
 request
In-Reply-To: <1464232091-24882-1-git-send-email-shawn.lin@rock-chips.com>
References: <CGME20160526030949epcas1p4960ec32140a9ac70ff7616031d667cfe@epcas1p4.samsung.com>
 <1464232091-24882-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <57479A84.4080207@samsung.com>

Hi Shawn,

On 05/26/2016 12:08 PM, Shawn Lin wrote:
> The main reason to add this check is to avoid unnecessary
> mmc_request if the card is removed. Although we have already
> check this in dw_mci_handle_cd for runtime usage of sd card and
> dw_mci_init_slot for noremovable devices, but there is a timing
> gap before it really calls dw_mci_get_cd as mmc_detect_change needs
> some delay here.

What's unnecessary mmc_request?

> 
> Another gain here is that we could save some checkings of card status
> after sd card been removed.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
> 
>  drivers/mmc/host/dw_mmc.c | 3 +++
>  1 file changed, 3 insertions(+)
> 
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index cb30e91..2940d24 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -105,6 +105,7 @@ struct idmac_desc {
>  static bool dw_mci_reset(struct dw_mci *host);
>  static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
>  static int dw_mci_card_busy(struct mmc_host *mmc);
> +static int dw_mci_get_cd(struct mmc_host *mmc);
>  
>  #if defined(CONFIG_DEBUG_FS)
>  static int dw_mci_req_show(struct seq_file *s, void *v)
> @@ -1248,6 +1249,8 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
>  
>  	WARN_ON(slot->mrq);
>  
> +	dw_mci_get_cd(mmc);
> +

If my understanding is right, it can be replaced 

if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags))

to

if (!dw_mci_get_cd(mmc))


Best Regards,
Jaehoon Chung



>  	/*
>  	 * The check for card presence and queueing of the request must be
>  	 * atomic, otherwise the card could be removed in between and the
> 



From shawn.lin at rock-chips.com  Thu May 26 19:24:19 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 27 May 2016 10:24:19 +0800
Subject: [RFC PATCH 1/2] mmc: dw_mmc: remove redundant of set_bit and
 clear_bit
In-Reply-To: <57479A7E.3050103@samsung.com>
References: <CGME20160526030828epcas1p16b97a230c35c2599a2b8fcada376c9de@epcas1p1.samsung.com>
 <1464232063-24841-1-git-send-email-shawn.lin@rock-chips.com>
 <57479A7E.3050103@samsung.com>
Message-ID: <cb3beb19-25a9-ec87-825c-bc485e5ba0f8@rock-chips.com>

? 2016/5/27 8:53, Jaehoon Chung ??:
> Hi Shawn,
>
> On 05/26/2016 12:07 PM, Shawn Lin wrote:
>> dw_mci_get_cd have already dealed with these for
>> both of internal card-detect and gpio card-detect.
>
> s/dealed/dealt
>
> This patch looks good to me. Could you resend the patch? not RFC.
>

Ok.

> Best Regards,
> Jaehoon Chung
>
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>
>> ---
>>
>>  drivers/mmc/host/dw_mmc.c | 5 +----
>>  1 file changed, 1 insertion(+), 4 deletions(-)
>>
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index 829a6ee..cb30e91 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -2616,10 +2616,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>>  		mmc->max_seg_size = mmc->max_req_size;
>>  	}
>>
>> -	if (dw_mci_get_cd(mmc))
>> -		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>> -	else
>> -		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
>> +	dw_mci_get_cd(mmc);
>>
>>  	ret = mmc_add_host(mmc);
>>  	if (ret)
>>
>
>
>
>


-- 
Best Regards
Shawn Lin



From shawn.lin at rock-chips.com  Thu May 26 19:26:58 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 27 May 2016 10:26:58 +0800
Subject: [RFC PATCH 2/2] mmc: dw_mmc: check card present before starting
 request
In-Reply-To: <57479A84.4080207@samsung.com>
References: <CGME20160526030949epcas1p4960ec32140a9ac70ff7616031d667cfe@epcas1p4.samsung.com>
 <1464232091-24882-1-git-send-email-shawn.lin@rock-chips.com>
 <57479A84.4080207@samsung.com>
Message-ID: <6c5f8e6c-efbc-667e-2a7b-00381e8a5646@rock-chips.com>

Hi Jaehoon,

On 2016/5/27 8:53, Jaehoon Chung wrote:
> Hi Shawn,
>
> On 05/26/2016 12:08 PM, Shawn Lin wrote:
>> The main reason to add this check is to avoid unnecessary
>> mmc_request if the card is removed. Although we have already
>> check this in dw_mci_handle_cd for runtime usage of sd card and
>> dw_mci_init_slot for noremovable devices, but there is a timing
>> gap before it really calls dw_mci_get_cd as mmc_detect_change needs
>> some delay here.
>
> What's unnecessary mmc_request?

the on-going read/write/ and the corresponding sbc like cmd13, etc.


>
>>
>> Another gain here is that we could save some checkings of card status
>> after sd card been removed.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> ---
>>
>>  drivers/mmc/host/dw_mmc.c | 3 +++
>>  1 file changed, 3 insertions(+)
>>
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index cb30e91..2940d24 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -105,6 +105,7 @@ struct idmac_desc {
>>  static bool dw_mci_reset(struct dw_mci *host);
>>  static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
>>  static int dw_mci_card_busy(struct mmc_host *mmc);
>> +static int dw_mci_get_cd(struct mmc_host *mmc);
>>
>>  #if defined(CONFIG_DEBUG_FS)
>>  static int dw_mci_req_show(struct seq_file *s, void *v)
>> @@ -1248,6 +1249,8 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
>>
>>  	WARN_ON(slot->mrq);
>>
>> +	dw_mci_get_cd(mmc);
>> +
>
> If my understanding is right, it can be replaced
>
> if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags))
>
> to
>
> if (!dw_mci_get_cd(mmc))

yeah~ It looks better.

>
>
> Best Regards,
> Jaehoon Chung
>
>
>
>>  	/*
>>  	 * The check for card presence and queueing of the request must be
>>  	 * atomic, otherwise the card could be removed in between and the
>>
>
>
>
>


-- 
Best Regards
Shawn Lin



From xzy.xu at rock-chips.com  Thu May 26 19:41:17 2016
From: xzy.xu at rock-chips.com (Ziyuan Xu)
Date: Fri, 27 May 2016 10:41:17 +0800
Subject: [PATCH] mmc: mmc: Fix HS switch failure in mmc_select_hs400()
In-Reply-To: <5746BC9D.9050501@intel.com>
References: <1464241832-10322-1-git-send-email-xzy.xu@rock-chips.com>
 <5746BC9D.9050501@intel.com>
Message-ID: <5747B3CD.9080102@rock-chips.com>



On 2016?05?26? 17:06, Adrian Hunter wrote:
> On 26/05/16 08:50, Ziyuan Xu wrote:
>> To slove the issue which was found on gru board for hs400.
>>
>> [    4.616946] sdhci: Secure Digital Host Controller Interface driver
>> [    4.623135] sdhci: Copyright(c) Pierre Ossman
>> [    4.722575] sdhci-pltfm: SDHCI platform and OF driver helper
>> [    4.730962] sdhci-arasan fe330000.sdhci: No vmmc regulator found
>> [    4.737444] sdhci-arasan fe330000.sdhci: No vqmmc regulator found
>> [    4.774930] mmc0: SDHCI controller on fe330000.sdhci [fe330000.sdhci] using ADMA
>> [    4.980295] mmc0: switch to high-speed from hs200 failed, err:-84
>> [    4.986487] mmc0: error -84 whilst initialising MMC card
>>
>> We should change HS400 mode selection timing to meet JEDEC
>> specification. The JEDEC 5.1 said that change the frequency to <= 52MHZ
>> after HS_TIMING switch. Refer to section 6.6.2.3 "HS400" timing mode
>> selection:
>> Set the "Timing Interface" parameter in the HS_TIMING[185] field of the
>> Extended CSD register to 0x1 to switch to High Speed mode and then set
>> the clock frequency to a value not greater than 52MHZ.
> Do you need a fix also for re-tuning? i.e. does re-tuning work with this
> patch? Or do you not need re-tuning?

Do you mean that revise the similar timing in mmc_hs400_to_hs200()as 
shown below?

diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index 8e4d059..4232a42 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -1161,10 +1161,6 @@ int mmc_hs400_to_hs200(struct mmc_card *card)
         if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
                 send_status = false;

-       /* Reduce frequency to HS */
-       max_dtr = card->ext_csd.hs_max_dtr;
-       mmc_set_clock(host, max_dtr);
-
         /* Switch HS400 to HS DDR */
         val = EXT_CSD_TIMING_HS;
         err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL, EXT_CSD_HS_TIMING,
@@ -1175,6 +1171,10 @@ int mmc_hs400_to_hs200(struct mmc_card *card)

         mmc_set_timing(host, MMC_TIMING_MMC_DDR52);

+       /* Reduce frequency to HS */
+       max_dtr = card->ext_csd.hs_max_dtr;
+       mmc_set_clock(host, max_dtr);
+
         if (!send_status) {
                 err = mmc_switch_status(card);
                 if (err)

The spec doesn't require mode selection from hs400 to hs200, moreover I 
have not yet hit any failure in mmc_hs400_to_hs200.
Thus I don't know whether a fix is needed for re-tuning.
By the way, what's your opinion for this patch?   I know, you did it on 
purpose that I found some message from git log.

>> Signed-off-by: Ziyuan Xu <xzy.xu at rock-chips.com>
>> ---
>>   drivers/mmc/core/mmc.c | 8 ++++----
>>   1 file changed, 4 insertions(+), 4 deletions(-)
>>
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index b81b08f..8e4d059 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -1078,10 +1078,6 @@ static int mmc_select_hs400(struct mmc_card *card)
>>   	if (host->caps & MMC_CAP_WAIT_WHILE_BUSY)
>>   		send_status = false;
>>   
>> -	/* Reduce frequency to HS frequency */
>> -	max_dtr = card->ext_csd.hs_max_dtr;
>> -	mmc_set_clock(host, max_dtr);
>> -
>>   	/* Switch card to HS mode */
>>   	val = EXT_CSD_TIMING_HS;
>>   	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> @@ -1097,6 +1093,10 @@ static int mmc_select_hs400(struct mmc_card *card)
>>   	/* Set host controller to HS timing */
>>   	mmc_set_timing(card->host, MMC_TIMING_MMC_HS);
>>   
>> +	/* Reduce frequency to HS frequency */
>> +	max_dtr = card->ext_csd.hs_max_dtr;
>> +	mmc_set_clock(host, max_dtr);
>> +
>>   	if (!send_status) {
>>   		err = mmc_switch_status(card);
>>   		if (err)
>>
>
>
>




From shawn.lin at rock-chips.com  Thu May 26 20:01:52 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 27 May 2016 11:01:52 +0800
Subject: [PATCH 1/2] mmc: dw_mmc: remove redundant of set_bit and clear_bit
Message-ID: <1464318112-5314-1-git-send-email-shawn.lin@rock-chips.com>

dw_mci_get_cd have already dealt with these for
both of internal card-detect and gpio card-detect.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

 drivers/mmc/host/dw_mmc.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 829a6ee..cb30e91 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2616,10 +2616,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 		mmc->max_seg_size = mmc->max_req_size;
 	}
 
-	if (dw_mci_get_cd(mmc))
-		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-	else
-		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+	dw_mci_get_cd(mmc);
 
 	ret = mmc_add_host(mmc);
 	if (ret)
-- 
2.3.7




From shawn.lin at rock-chips.com  Thu May 26 20:02:21 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 27 May 2016 11:02:21 +0800
Subject: [PATCH 2/2] mmc: dw_mmc: check card present before starting request
Message-ID: <1464318141-5360-1-git-send-email-shawn.lin@rock-chips.com>

The main reason to add this check is to avoid unnecessary
mmc_request like the on-going cmd and the corresponding sbc
if the card is removed. Although we have already checked this in
dw_mci_handle_cd for runtime usage of sd card and dw_mci_init_slot
for noremovable devices, but there is a timing gap before it really
calls dw_mci_get_cd as mmc_detect_change needs some delay here.

Another gain here is that we could save some checkings of card status
after sd card been removed.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
---

 drivers/mmc/host/dw_mmc.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index cb30e91..8eb7898 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -105,6 +105,7 @@ struct idmac_desc {
 static bool dw_mci_reset(struct dw_mci *host);
 static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
 static int dw_mci_card_busy(struct mmc_host *mmc);
+static int dw_mci_get_cd(struct mmc_host *mmc);
 
 #if defined(CONFIG_DEBUG_FS)
 static int dw_mci_req_show(struct seq_file *s, void *v)
@@ -1255,7 +1256,7 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 	 */
 	spin_lock_bh(&host->lock);
 
-	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
+	if (!dw_mci_get_cd(mmc)) {
 		spin_unlock_bh(&host->lock);
 		mrq->cmd->error = -ENOMEDIUM;
 		mmc_request_done(mmc, mrq);
-- 
2.3.7




From jh80.chung at samsung.com  Thu May 26 20:46:14 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Fri, 27 May 2016 12:46:14 +0900
Subject: [PATCH 2/2] mmc: dw_mmc: check card present before starting
 request
In-Reply-To: <1464318141-5360-1-git-send-email-shawn.lin@rock-chips.com>
References: <CGME20160527030403epcas1p48a308b374e994de0e9e80b1b7ff1da10@epcas1p4.samsung.com>
 <1464318141-5360-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <5747C306.7030909@samsung.com>

Hi Shawn,

On 05/27/2016 12:02 PM, Shawn Lin wrote:
> The main reason to add this check is to avoid unnecessary
> mmc_request like the on-going cmd and the corresponding sbc
> if the card is removed. Although we have already checked this in
> dw_mci_handle_cd for runtime usage of sd card and dw_mci_init_slot
> for noremovable devices, but there is a timing gap before it really
> calls dw_mci_get_cd as mmc_detect_change needs some delay here.
> 
> Another gain here is that we could save some checkings of card status
> after sd card been removed.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
> 
>  drivers/mmc/host/dw_mmc.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index cb30e91..8eb7898 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -105,6 +105,7 @@ struct idmac_desc {
>  static bool dw_mci_reset(struct dw_mci *host);
>  static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
>  static int dw_mci_card_busy(struct mmc_host *mmc);
> +static int dw_mci_get_cd(struct mmc_host *mmc);
>  
>  #if defined(CONFIG_DEBUG_FS)
>  static int dw_mci_req_show(struct seq_file *s, void *v)
> @@ -1255,7 +1256,7 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
>  	 */
>  	spin_lock_bh(&host->lock);
>  
> -	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
> +	if (!dw_mci_get_cd(mmc)) {
>  		spin_unlock_bh(&host->lock);
>  		mrq->cmd->error = -ENOMEDIUM;
>  		mmc_request_done(mmc, mrq);

I think spin_lock/unlock_bh() should be removed at here.
Instead, Can it locate before calling dw_mci_queue_request()?

Anyway, it looks good to me.

Best Regards,
Jaehoon Chung

> 



From shawn.lin at rock-chips.com  Thu May 26 21:13:18 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 27 May 2016 12:13:18 +0800
Subject: [PATCH 2/2] mmc: dw_mmc: check card present before starting
 request
In-Reply-To: <5747C306.7030909@samsung.com>
References: <CGME20160527030403epcas1p48a308b374e994de0e9e80b1b7ff1da10@epcas1p4.samsung.com>
 <1464318141-5360-1-git-send-email-shawn.lin@rock-chips.com>
 <5747C306.7030909@samsung.com>
Message-ID: <e130d6fa-3fca-9925-603e-8f410cfb0297@rock-chips.com>

? 2016/5/27 11:46, Jaehoon Chung ??:
> Hi Shawn,
>
> On 05/27/2016 12:02 PM, Shawn Lin wrote:
>> The main reason to add this check is to avoid unnecessary
>> mmc_request like the on-going cmd and the corresponding sbc
>> if the card is removed. Although we have already checked this in
>> dw_mci_handle_cd for runtime usage of sd card and dw_mci_init_slot
>> for noremovable devices, but there is a timing gap before it really
>> calls dw_mci_get_cd as mmc_detect_change needs some delay here.
>>
>> Another gain here is that we could save some checkings of card status
>> after sd card been removed.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>> ---
>>
>>  drivers/mmc/host/dw_mmc.c | 3 ++-
>>  1 file changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
>> index cb30e91..8eb7898 100644
>> --- a/drivers/mmc/host/dw_mmc.c
>> +++ b/drivers/mmc/host/dw_mmc.c
>> @@ -105,6 +105,7 @@ struct idmac_desc {
>>  static bool dw_mci_reset(struct dw_mci *host);
>>  static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
>>  static int dw_mci_card_busy(struct mmc_host *mmc);
>> +static int dw_mci_get_cd(struct mmc_host *mmc);
>>
>>  #if defined(CONFIG_DEBUG_FS)
>>  static int dw_mci_req_show(struct seq_file *s, void *v)
>> @@ -1255,7 +1256,7 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
>>  	 */
>>  	spin_lock_bh(&host->lock);
>>
>> -	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
>> +	if (!dw_mci_get_cd(mmc)) {
>>  		spin_unlock_bh(&host->lock);
>>  		mrq->cmd->error = -ENOMEDIUM;
>>  		mmc_request_done(mmc, mrq);
>
> I think spin_lock/unlock_bh() should be removed at here.

yes, we should hole the lock before dw_mci_queue_request as
dw_mci_get_cd release it, in which state we do the minmum changes
for achieving what we need here.

I will fix it.

> Instead, Can it locate before calling dw_mci_queue_request()?
>
> Anyway, it looks good to me.
>
> Best Regards,
> Jaehoon Chung
>
>>
>
>
>
>


-- 
Best Regards
Shawn Lin



From zyw at rock-chips.com  Thu May 26 23:02:13 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 14:02:13 +0800
Subject: [PATCH 0/6] Rockchip Type-C and DispplayPort driver
Message-ID: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>

Hi all

This series patch is for rockchip Type-C phy and DisplayPort controller
driver.

The USB Type-C PHY is designed to support the USB3 and DP applications.
The PHY basically has two main components: USB3 and DisplyPort. USB3
operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2
data rates. The Type-C cable orientation detection and Power Delivery
(PD) is accomplished using a PD PHY or a exernal PD chip.

The DP controller is compliant with DisplayPort Specification,
Version 1.3, This IP is compatible with the rockchip type-c PHY IP.
There is a uCPU in DP controller, it need a firmware to work, please
put the firmware file to /lib/firmware/cdn/dptx.bin. The uCPU in charge
of aux communication and link training, the host use mailbox to
communicate with the ucpu.

The PHY driver has register a notification, to get the alt mode from PD,
the PD driver need call the tcphy_notifier_call_chain to notify PHY and
DP controller.

This series is based on Mark Yao's branch:
https://github.com/markyzq/kernel-drm-rockchip/tree/drm-rockchip-next-2016-05-23

I test this patches on the rk3399-evb board, with a fusb302 driver,
this branch has no rk3399.dtsi, so the patch about dts is not included
in this series.



Chris Zhong (6):
  phy: Add USB Type-C PHY driver for rk3399
  Documentation: bindings: add dt doc for Rockchip USB Type-C PHY
  drm/rockchip: vop: add cdn DP support for rk3399
  Documentation: bindings: add dt documentation for cdn DP controller
  ASoC: cdn-dp: Add cdn DP codec driver
  ASoC: rockchip: Add machine driver for cdn dp codec

 .../bindings/display/rockchip/cdn-dp-rockchip.txt  |  57 ++
 .../devicetree/bindings/phy/phy-rockchip-typec.txt |  55 ++
 .../bindings/sound/rockchip-cdn-dp-audio.txt       |  12 +
 drivers/gpu/drm/rockchip/Kconfig                   |   9 +
 drivers/gpu/drm/rockchip/Makefile                  |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c             | 620 ++++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-core.h             |  95 +++
 drivers/gpu/drm/rockchip/cdn-dp-reg.c              | 730 ++++++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-reg.h              | 404 ++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |   9 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h        |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c        |   2 +
 drivers/phy/Kconfig                                |   7 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/phy-rockchip-typec.c                   | 823 +++++++++++++++++++++
 include/sound/cdn-dp-audio.h                       |  51 ++
 sound/soc/codecs/Kconfig                           |   3 +
 sound/soc/codecs/Makefile                          |   2 +
 sound/soc/codecs/cdn-dp-audio.c                    | 246 ++++++
 sound/soc/rockchip/Kconfig                         |   9 +
 sound/soc/rockchip/Makefile                        |   2 +
 sound/soc/rockchip/rockchip-cdn-dp-audio.c         | 167 +++++
 22 files changed, 3306 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip-cdn-dp-audio.txt
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.h
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.h
 create mode 100644 drivers/phy/phy-rockchip-typec.c
 create mode 100644 include/sound/cdn-dp-audio.h
 create mode 100644 sound/soc/codecs/cdn-dp-audio.c
 create mode 100644 sound/soc/rockchip/rockchip-cdn-dp-audio.c

-- 
2.6.3



From zyw at rock-chips.com  Thu May 26 23:02:14 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 14:02:14 +0800
Subject: [PATCH 1/6] phy: Add USB Type-C PHY driver for rk3399
In-Reply-To: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464328939-8073-2-git-send-email-zyw@rock-chips.com>

Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB
Type-C PHY is designed to support the USB3 and DP applications. The
PHY basically has two main components: USB3 and DisplyPort. USB3
operates in SuperSpeed mode and the DP can operate at RBR, HBR and
HBR2 data rates.

Signed-off-by: Chris Zhong <zyw at rock-chips.com>
---

 drivers/phy/Kconfig              |   7 +
 drivers/phy/Makefile             |   1 +
 drivers/phy/phy-rockchip-typec.c | 823 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 831 insertions(+)
 create mode 100644 drivers/phy/phy-rockchip-typec.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 26566db..dc388a3d 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -351,6 +351,13 @@ config PHY_ROCKCHIP_DP
 	help
 	  Enable this to support the Rockchip Display Port PHY.
 
+config PHY_ROCKCHIP_TYPEC
+	tristate "Rockchip TYPEC PHY Driver"
+	depends on ARCH_ROCKCHIP && OF
+	select GENERIC_PHY
+	help
+	  Enable this to support the Rockchip USB TYPEC PHY.
+
 config PHY_ST_SPEAR1310_MIPHY
 	tristate "ST SPEAR1310-MIPHY driver"
 	select GENERIC_PHY
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 24596a9..91fa413 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
 obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
 obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
 obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
+obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
 obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
 obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)	+= phy-spear1310-miphy.o
 obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
diff --git a/drivers/phy/phy-rockchip-typec.c b/drivers/phy/phy-rockchip-typec.c
new file mode 100644
index 0000000..6609cfb
--- /dev/null
+++ b/drivers/phy/phy-rockchip-typec.c
@@ -0,0 +1,823 @@
+/*
+ * Rockchip usb3 PHY driver
+ *
+ * Copyright (C) 2016 Kever Yang <kever.yang at rock-chips.com>
+ *                    Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/delay.h>
+#include <linux/phy/phy-rockchip-typec.h>
+
+#define ADDR_ADJ			2
+#define CMN_SSM_BANDGAP			(0x21 << ADDR_ADJ)
+#define CMN_SSM_BIAS			(0x22 << ADDR_ADJ)
+#define CMN_PLLSM0_PLLEN		(0x29 << ADDR_ADJ)
+#define CMN_PLLSM0_PLLPRE		(0x2a << ADDR_ADJ)
+#define CMN_PLLSM0_PLLVREF		(0x2b << ADDR_ADJ)
+#define CMN_PLLSM0_PLLLOCK		(0x2c << ADDR_ADJ)
+#define CMN_PLLSM1_PLLEN		(0x31 << ADDR_ADJ)
+#define CMN_PLLSM1_PLLPRE		(0x32 << ADDR_ADJ)
+#define CMN_PLLSM1_PLLVREF		(0x33 << ADDR_ADJ)
+#define CMN_PLLSM1_PLLLOCK		(0x34 << ADDR_ADJ)
+#define CMN_PLLSM1_USER_DEF_CTRL	(0x37 << ADDR_ADJ)
+#define CMN_ICAL_OVRD			(0xc1 << ADDR_ADJ)
+#define CMN_PLL0_VCOCAL_OVRD		(0x83 << ADDR_ADJ)
+#define CMN_PLL0_VCOCAL_INIT		(0x84 << ADDR_ADJ)
+#define CMN_PLL0_VCOCAL_ITER		(0x85 << ADDR_ADJ)
+#define CMN_PLL0_LOCK_REFCNT_START	(0x90 << ADDR_ADJ)
+#define CMN_PLL0_LOCK_PLLCNT_START	(0x92 << ADDR_ADJ)
+#define CMN_PLL0_LOCK_PLLCNT_THR	(0x93 << ADDR_ADJ)
+#define CMN_PLL0_INTDIV			(0x94 << ADDR_ADJ)
+#define CMN_PLL0_FRACDIV		(0x95 << ADDR_ADJ)
+#define CMN_PLL0_HIGH_THR		(0x96 << ADDR_ADJ)
+#define CMN_PLL0_DSM_DIAG		(0x97 << ADDR_ADJ)
+#define CMN_PLL0_SS_CTRL1		(0x98 << ADDR_ADJ)
+#define CMN_PLL0_SS_CTRL2		(0x99 << ADDR_ADJ)
+#define CMN_PLL1_VCOCAL_START		(0xa1 << ADDR_ADJ)
+#define CMN_PLL1_VCOCAL_OVRD		(0xa3 << ADDR_ADJ)
+#define CMN_PLL1_VCOCAL_INIT		(0xa4 << ADDR_ADJ)
+#define CMN_PLL1_VCOCAL_ITER		(0xa5 << ADDR_ADJ)
+#define CMN_PLL1_LOCK_REFCNT_START	(0xb0 << ADDR_ADJ)
+#define CMN_PLL1_LOCK_PLLCNT_START	(0xb2 << ADDR_ADJ)
+#define CMN_PLL1_LOCK_PLLCNT_THR	(0xb3 << ADDR_ADJ)
+#define CMN_PLL1_INTDIV			(0xb4 << ADDR_ADJ)
+#define CMN_PLL1_FRACDIV		(0xb5 << ADDR_ADJ)
+#define CMN_PLL1_HIGH_THR		(0xb6 << ADDR_ADJ)
+#define CMN_PLL1_DSM_DIAG		(0xb7 << ADDR_ADJ)
+#define CMN_PLL1_SS_CTRL1		(0xb8 << ADDR_ADJ)
+#define CMN_PLL1_SS_CTRL2		(0xb9 << ADDR_ADJ)
+#define CMN_RXCAL_OVRD			(0xd1 << ADDR_ADJ)
+#define CMN_TXPUCAL_CTRL		(0xe0 << ADDR_ADJ)
+#define CMN_TXPUCAL_OVRD		(0xe1 << ADDR_ADJ)
+#define CMN_TXPDCAL_OVRD		(0xf1 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_FBH_OVRD		(0x1c0 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_FBL_OVRD		(0x1c1 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_OVRD		(0x1c2 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_V2I_TUNE		(0x1c5 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_CP_TUNE		(0x1c6 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_LF_PROG		(0x1c7 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_FBH_OVRD		(0x1d0 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_FBL_OVRD		(0x1d1 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_OVRD		(0x1d2 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_V2I_TUNE		(0x1d5 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_CP_TUNE		(0x1d6 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_LF_PROG		(0x1d7 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_PTATIS_TUNE1	(0x1d8 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_PTATIS_TUNE2	(0x1d9 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_INCLK_CTRL	(0x1da << ADDR_ADJ)
+#define CMN_DIAG_HSCLK_SEL		(0x1e0 << ADDR_ADJ)
+
+#define XCVR_PSM_RCTRL(n)		((0x4001 | (n << 9)) << ADDR_ADJ)
+#define XCVR_PSM_CAL_TMR(n)		((0x4002 | (n << 9)) << ADDR_ADJ)
+#define XCVR_PSM_A0IN_TMR(n)		((0x4003 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_CAL_SCLR_MULT(n)	((0x4047 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_CPOST_MULT_00(n)	((0x404c | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_CPOST_MULT_01(n)	((0x404d | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_CPOST_MULT_10(n)	((0x404e | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_CPOST_MULT_11(n)	((0x404f | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_000(n)	((0x4050 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_001(n)	((0x4051 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_010(n)	((0x4052 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_011(n)	((0x4053 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_100(n)	((0x4054 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_101(n)	((0x4055 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_110(n)	((0x4056 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_111(n)	((0x4057 | (n << 9)) << ADDR_ADJ)
+#define XCVR_DIAG_PLLDRC_CTRL(n)	((0x40e0 | (n << 9)) << ADDR_ADJ)
+#define XCVR_DIAG_BIDI_CTRL(n)		((0x40e8 | (n << 9)) << ADDR_ADJ)
+#define XCVR_DIAG_LANE_FCM_EN_MGN(n)	((0x40f2 | (n << 9)) << ADDR_ADJ)
+#define TX_PSC_A0(n)			((0x4100 | (n << 9)) << ADDR_ADJ)
+#define TX_PSC_A1(n)			((0x4101 | (n << 9)) << ADDR_ADJ)
+#define TX_PSC_A2(n)			((0x4102 | (n << 9)) << ADDR_ADJ)
+#define TX_PSC_A3(n)			((0x4103 | (n << 9)) << ADDR_ADJ)
+#define TX_RCVDET_CTRL(n)		((0x4120 | (n << 9)) << ADDR_ADJ)
+#define TX_RCVDET_EN_TMR(n)		((0x4122 | (n << 9)) << ADDR_ADJ)
+#define TX_RCVDET_ST_TMR(n)		((0x4123 | (n << 9)) << ADDR_ADJ)
+#define TX_DIAG_TX_DRV(n)		((0x41e1 | (n << 9)) << ADDR_ADJ)
+#define TX_DIAG_BGREF_PREDRV_DELAY	(0x41e7 << ADDR_ADJ)
+#define TX_ANA_CTRL_REG_1		(0x5020 << ADDR_ADJ)
+#define TX_ANA_CTRL_REG_2		(0x5021 << ADDR_ADJ)
+#define TXDA_COEFF_CALC_CTRL		(0x5022 << ADDR_ADJ)
+#define TX_DIG_CTRL_REG_2		(0x5024 << ADDR_ADJ)
+#define TXDA_CYA_AUXDA_CYA		(0x5025 << ADDR_ADJ)
+#define TX_ANA_CTRL_REG_3		(0x5026 << ADDR_ADJ)
+#define TX_ANA_CTRL_REG_4		(0x5027 << ADDR_ADJ)
+#define TX_ANA_CTRL_REG_5		(0x5029 << ADDR_ADJ)
+
+#define RX_PSC_A0(n)			((0x8000 | (n << 9)) << ADDR_ADJ)
+#define RX_PSC_A1(n)			((0x8001 | (n << 9)) << ADDR_ADJ)
+#define RX_PSC_A2(n)			((0x8002 | (n << 9)) << ADDR_ADJ)
+#define RX_PSC_A3(n)			((0x8003 | (n << 9)) << ADDR_ADJ)
+#define RX_PSC_CAL(n)			((0x8006 | (n << 9)) << ADDR_ADJ)
+#define RX_PSC_RDY(n)			((0x8007 | (n << 9)) << ADDR_ADJ)
+#define RX_IQPI_ILL_CAL_OVRD		(0x8023 << ADDR_ADJ)
+#define RX_EPI_ILL_CAL_OVRD		(0x8033 << ADDR_ADJ)
+#define RX_SDCAL0_OVRD			(0x8041 << ADDR_ADJ)
+#define RX_SDCAL1_OVRD			(0x8049 << ADDR_ADJ)
+#define RX_SLC_INIT			(0x806d << ADDR_ADJ)
+#define RX_SLC_RUN			(0x806e << ADDR_ADJ)
+#define RX_CDRLF_CNFG2			(0x8081 << ADDR_ADJ)
+#define RX_SIGDET_HL_FILT_TMR(n)	((0x8090 | (n << 9)) << ADDR_ADJ)
+#define RX_SLC_IOP0_OVRD		(0x8101 << ADDR_ADJ)
+#define RX_SLC_IOP1_OVRD		(0x8105 << ADDR_ADJ)
+#define RX_SLC_QOP0_OVRD		(0x8109 << ADDR_ADJ)
+#define RX_SLC_QOP1_OVRD		(0x810d << ADDR_ADJ)
+#define RX_SLC_EOP0_OVRD		(0x8111 << ADDR_ADJ)
+#define RX_SLC_EOP1_OVRD		(0x8115 << ADDR_ADJ)
+#define RX_SLC_ION0_OVRD		(0x8119 << ADDR_ADJ)
+#define RX_SLC_ION1_OVRD		(0x811d << ADDR_ADJ)
+#define RX_SLC_QON0_OVRD		(0x8121 << ADDR_ADJ)
+#define RX_SLC_QON1_OVRD		(0x8125 << ADDR_ADJ)
+#define RX_SLC_EON0_OVRD		(0x8129 << ADDR_ADJ)
+#define RX_SLC_EON1_OVRD		(0x812d << ADDR_ADJ)
+#define RX_SLC_IEP0_OVRD		(0x8131 << ADDR_ADJ)
+#define RX_SLC_IEP1_OVRD		(0x8135 << ADDR_ADJ)
+#define RX_SLC_QEP0_OVRD		(0x8139 << ADDR_ADJ)
+#define RX_SLC_QEP1_OVRD		(0x813d << ADDR_ADJ)
+#define RX_SLC_EEP0_OVRD		(0x8141 << ADDR_ADJ)
+#define RX_SLC_EEP1_OVRD		(0x8145 << ADDR_ADJ)
+#define RX_SLC_IEN0_OVRD		(0x8149 << ADDR_ADJ)
+#define RX_SLC_IEN1_OVRD		(0x814d << ADDR_ADJ)
+#define RX_SLC_QEN0_OVRD		(0x8151 << ADDR_ADJ)
+#define RX_SLC_QEN1_OVRD		(0x8155 << ADDR_ADJ)
+#define RX_SLC_EEN0_OVRD		(0x8159 << ADDR_ADJ)
+#define RX_SLC_EEN1_OVRD		(0x815d << ADDR_ADJ)
+#define RX_DIAG_SIGDET_TUNE(n)		((0x81dc | (n << 9)) << ADDR_ADJ)
+#define RX_DIAG_SC2C_DELAY		(0x81e1 << ADDR_ADJ)
+
+#define PMA_LANE_CFG			(0xc000 << ADDR_ADJ)
+#define PIPE_CMN_CTRL1			(0xc001 << ADDR_ADJ)
+#define PIPE_CMN_CTRL2			(0xc002 << ADDR_ADJ)
+#define PIPE_COM_LOCK_CFG1		(0xc003 << ADDR_ADJ)
+#define PIPE_COM_LOCK_CFG2		(0xc004 << ADDR_ADJ)
+#define PIPE_RCV_DET_INH		(0xc005 << ADDR_ADJ)
+#define DP_MODE_CTL			(0xc008 << ADDR_ADJ)
+#define DP_CLK_CTL			(0xc009 << ADDR_ADJ)
+#define STS				(0xc00F << ADDR_ADJ)
+#define PHY_ISO_CMN_CTRL		(0xc010 << ADDR_ADJ)
+#define PHY_DP_TX_CTL			(0xc408 << ADDR_ADJ)
+#define PMA_CMN_CTRL1			(0xc800 << ADDR_ADJ)
+#define PHY_PMA_ISO_CMN_CTRL		(0xc810 << ADDR_ADJ)
+#define PHY_ISOLATION_CTRL		(0xc81f << ADDR_ADJ)
+#define PHY_PMA_ISO_XCVR_CTRL(n)	((0xcc11 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_LINK_MODE(n)	((0xcc12 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_PWRST_CTRL(n)	((0xcc13 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_TX_DATA_LO(n)	((0xcc14 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_TX_DATA_HI(n)	((0xcc15 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_RX_DATA_LO(n)	((0xcc16 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_RX_DATA_HI(n)	((0xcc17 | (n << 6)) << ADDR_ADJ)
+#define TX_BIST_CTRL(n)			((0x4140 | (n << 9)) << ADDR_ADJ)
+#define TX_BIST_UDDWR(n)		((0x4141 | (n << 9)) << ADDR_ADJ)
+
+#define GRF_SOC_CON26			0x6268
+#define UPHY_DP_SEL			BIT(3)
+#define UPHY_DP_SEL_MASK		BIT(19)
+#define DPTX_HDP_SEL			(3 << 12)
+#define DPTX_HDP_SEL_MASK		(3 << 28)
+
+#define PHY_MODE_SET_TIMEOUT		1000000
+
+#define	MODE_DISCONNECT			1
+#define	MODE_UFP			2
+#define	MODE_DFP_USBONLY		3
+#define	MODE_DFP_DPONLY			4
+#define	MODE_DFP_USB3DP			5
+#define	MODE_DFP_USB2DP			6
+
+#define PARSE_GRF_REG(TYPE) { \
+	if (of_find_property(np, "rockchip,usb3phy_"#TYPE, &len)) { \
+		len /= sizeof(u32);\
+		ret = of_property_read_u32_array(np, "rockchip,usb3phy_" #TYPE,\
+						 array, len); \
+		exregs->usb3phy_##TYPE = array[0]; \
+		exregs->usb3phy_##TYPE##_shift = array[1]; \
+		exregs->usb3phy_##TYPE##_mask = array[2]; \
+		pr_info("%s property found %s, %x, %d, %d\n", __func__, \
+			"rockchip,usb3phy_"#TYPE, \
+			array[0], array[1], array[2]); \
+	} else { \
+		pr_info("%s property not found %s\n", __func__, \
+			"rockchip,usb3phy_" #TYPE); \
+	} \
+}
+
+struct rockchip_typec_phy *rockchip_tcphy;
+
+static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy,
+			  unsigned int num_lanes)
+{
+	unsigned int i;
+
+	writel(0x830, tcphy->base + PMA_CMN_CTRL1);
+	for (i = 0; i < num_lanes; i++) {
+		writel(0x90, tcphy->base + XCVR_DIAG_LANE_FCM_EN_MGN(i));
+		writel(0x960, tcphy->base + TX_RCVDET_EN_TMR(i));
+		writel(0x30, tcphy->base + TX_RCVDET_ST_TMR(i));
+	}
+}
+
+static void tcphy_cfg_usb_pll(struct rockchip_typec_phy *tcphy)
+{
+	unsigned int rdata;
+
+	rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
+	writel(rdata & 0xfffc, tcphy->base + CMN_DIAG_HSCLK_SEL);
+	writel(0xf0, tcphy->base + CMN_PLL0_VCOCAL_INIT);
+	writel(0x18, tcphy->base + CMN_PLL0_VCOCAL_ITER);
+	writel(0xd0, tcphy->base + CMN_PLL0_INTDIV);
+	writel(0x4a4a, tcphy->base + CMN_PLL0_FRACDIV);
+	writel(0x34, tcphy->base + CMN_PLL0_HIGH_THR);
+	writel(0x1ee, tcphy->base + CMN_PLL0_SS_CTRL1);
+	writel(0x7f03, tcphy->base + CMN_PLL0_SS_CTRL2);
+	writel(0x20, tcphy->base + CMN_PLL0_DSM_DIAG);
+	writel(0, tcphy->base + CMN_DIAG_PLL0_OVRD);
+	writel(0, tcphy->base + CMN_DIAG_PLL0_FBH_OVRD);
+	writel(0, tcphy->base + CMN_DIAG_PLL0_FBL_OVRD);
+	writel(0x7, tcphy->base + CMN_DIAG_PLL0_V2I_TUNE);
+	writel(0x45, tcphy->base + CMN_DIAG_PLL0_CP_TUNE);
+	writel(0x8, tcphy->base + CMN_DIAG_PLL0_LF_PROG);
+}
+
+static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy)
+{
+	unsigned int rdata;
+
+	writel(0x2405, tcphy->base + DP_CLK_CTL);
+
+	rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
+	rdata = (rdata & 0xffcf) | 0x30;
+	writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL);
+	writel(0xf0, tcphy->base + CMN_PLL1_VCOCAL_INIT);
+	writel(0x18, tcphy->base + CMN_PLL1_VCOCAL_ITER);
+	writel(0x30b9, tcphy->base + CMN_PLL1_VCOCAL_START);
+	writel(0x21c, tcphy->base + CMN_PLL1_INTDIV);
+	writel(0, tcphy->base + CMN_PLL1_FRACDIV);
+	writel(0x5, tcphy->base + CMN_PLL1_HIGH_THR);
+	writel(0x35, tcphy->base + CMN_PLL1_SS_CTRL1);
+	writel(0x7f1e, tcphy->base + CMN_PLL1_SS_CTRL2);
+	writel(0x20, tcphy->base + CMN_PLL1_DSM_DIAG);
+	writel(0, tcphy->base + CMN_PLLSM1_USER_DEF_CTRL);
+	writel(0, tcphy->base + CMN_DIAG_PLL1_OVRD);
+	writel(0, tcphy->base + CMN_DIAG_PLL1_FBH_OVRD);
+	writel(0, tcphy->base + CMN_DIAG_PLL1_FBL_OVRD);
+	writel(0x6, tcphy->base + CMN_DIAG_PLL1_V2I_TUNE);
+	writel(0x45, tcphy->base + CMN_DIAG_PLL1_CP_TUNE);
+	writel(0x8, tcphy->base + CMN_DIAG_PLL1_LF_PROG);
+	writel(0x100, tcphy->base + CMN_DIAG_PLL1_PTATIS_TUNE1);
+	writel(0x7, tcphy->base + CMN_DIAG_PLL1_PTATIS_TUNE2);
+	writel(0x4, tcphy->base + CMN_DIAG_PLL1_INCLK_CTRL);
+}
+
+static void tcphy_tx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
+				  unsigned int lane)
+{
+	writel(0x7799, tcphy->base + TX_PSC_A0(lane));
+	writel(0x7798, tcphy->base + TX_PSC_A1(lane));
+	writel(0x5098, tcphy->base + TX_PSC_A2(lane));
+	writel(0x5098, tcphy->base + TX_PSC_A3(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
+	writel(0xbf, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
+}
+
+static void tcphy_rx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
+				  unsigned int lane)
+{
+	writel(0xa6fd, tcphy->base + RX_PSC_A0(lane));
+	writel(0xa6fd, tcphy->base + RX_PSC_A1(lane));
+	writel(0xa410, tcphy->base + RX_PSC_A2(lane));
+	writel(0x2410, tcphy->base + RX_PSC_A3(lane));
+	writel(0x23ff, tcphy->base + RX_PSC_CAL(lane));
+	writel(0x13, tcphy->base + RX_SIGDET_HL_FILT_TMR(lane));
+	writel(0x1004, tcphy->base + RX_DIAG_SIGDET_TUNE(lane));
+	writel(0x2010, tcphy->base + RX_PSC_RDY(lane));
+	writel(0xfb, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
+}
+
+static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy,
+			      unsigned int lane)
+{
+	unsigned int rdata;
+
+	writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane));
+	writel(0x6799, tcphy->base + TX_PSC_A0(lane));
+	writel(0x6798, tcphy->base + TX_PSC_A1(lane));
+	writel(0x98, tcphy->base + TX_PSC_A2(lane));
+	writel(0x98, tcphy->base + TX_PSC_A3(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_001(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_010(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_011(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_100(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_101(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_110(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_111(lane));
+
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_10(lane));
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_01(lane));
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_00(lane));
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_11(lane));
+
+	writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane));
+	writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane));
+
+	rdata = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
+	rdata = (rdata & 0x8fff) | 0x6000;
+	writel(rdata, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
+}
+
+static void tcphy_cfg_pin_assign(struct rockchip_typec_phy *tcphy)
+{
+	switch (tcphy->map) {
+	case PIN_MAP_A:
+		writel(0x19d5, tcphy->base + PMA_LANE_CFG);
+		break;
+	case PIN_MAP_B:
+		writel(0x1500, tcphy->base + PMA_LANE_CFG);
+		break;
+	case PIN_MAP_C:
+	case PIN_MAP_E:
+		writel(0x51d9, tcphy->base + PMA_LANE_CFG);
+		break;
+	case PIN_MAP_D:
+	case PIN_MAP_F:
+		writel(0x5100, tcphy->base + PMA_LANE_CFG);
+		break;
+	};
+}
+
+static void tcphy_cfg_lanes(struct rockchip_typec_phy *tcphy,
+			    unsigned int link_cfg)
+{
+	unsigned int i;
+
+	/* PMA lane configuration DP or USB3 */
+	for (i = 0; i < 4; i++) {
+		if ((link_cfg >> i) & 0x1) {
+			tcphy_dp_cfg_lane(tcphy, i);
+		} else {
+			/*
+			 * lan0 TX and lan1 RX for USB3 Normal direction
+			 * lan3 TX and lan2 RX for USB3 Flip direction
+			 */
+			if ((i == 0) | (i == 3))
+				tcphy_tx_usb_cfg_lane(tcphy, i);
+			else
+				tcphy_rx_usb_cfg_lane(tcphy, i);
+		}
+	}
+}
+
+static void tcphy_cfg_flip_set(struct rockchip_typec_phy *tcphy)
+{
+	regmap_write(tcphy->grf_regs,
+		     tcphy->exregs.usb3phy_con0,
+		     tcphy->flip | BIT(16));
+
+	tcphy_cfg_24m(tcphy, 0x4);
+
+	if (tcphy->mode == MODE_UFP ||
+	    tcphy->mode == MODE_DFP_USBONLY ||
+	    tcphy->mode == MODE_DFP_USB3DP)
+		tcphy_cfg_usb_pll(tcphy);
+
+	if (tcphy->mode == MODE_DFP_DPONLY ||
+	    tcphy->mode == MODE_DFP_USB2DP ||
+	    tcphy->mode == MODE_DFP_USB3DP)
+		tcphy_cfg_dp_pll(tcphy);
+
+	if (tcphy->mode == MODE_DFP_DPONLY || tcphy->mode == MODE_DFP_USB2DP)
+		tcphy_cfg_lanes(tcphy, 0xf);
+	else if (tcphy->flip)
+		tcphy_cfg_lanes(tcphy, 0x3);
+	else
+		tcphy_cfg_lanes(tcphy, 0xc);
+}
+
+static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
+{
+	int rdata, rdata2, val;
+
+	rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
+	rdata2 = readl(tcphy->base + CMN_TXPUCAL_CTRL);
+
+	rdata = rdata & 0xdfff;
+	writel(rdata, tcphy->base + TX_ANA_CTRL_REG_1);
+
+	rdata = readl(tcphy->base + TX_DIG_CTRL_REG_2);
+	rdata = rdata & 0xffc0;
+	rdata2 = rdata2 & 0x3f;
+	rdata  = rdata | rdata2;
+	writel(rdata, tcphy->base + TX_DIG_CTRL_REG_2);
+	usleep_range(1000, 2000);
+
+	rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
+	rdata = rdata | 0x2000;
+	writel(rdata, tcphy->base + TX_ANA_CTRL_REG_1);
+
+	usleep_range(150, 200);
+
+	writel(0, tcphy->base + PHY_DP_TX_CTL);
+	writel(0x100, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0x300, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
+	writel(0x2008, tcphy->base + TX_ANA_CTRL_REG_1);
+	writel(0x2018, tcphy->base + TX_ANA_CTRL_REG_1);
+	writel(0x30C, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
+	writel(0x1001, tcphy->base + TX_ANA_CTRL_REG_4);
+	writel(0x2098, tcphy->base + TX_ANA_CTRL_REG_1);
+	writel(0x2198, tcphy->base + TX_ANA_CTRL_REG_1);
+	writel(0x30d, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0x30f, tcphy->base + TX_ANA_CTRL_REG_2);
+
+	if (tcphy->flip)
+		writel(0xa078, tcphy->base + TX_ANA_CTRL_REG_1);
+	else
+		writel(0xb078, tcphy->base + TX_ANA_CTRL_REG_1);
+
+	writel(0x303, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_4);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
+	writel(4, tcphy->base + TXDA_COEFF_CALC_CTRL);
+	writel(0, tcphy->base + TXDA_CYA_AUXDA_CYA);
+
+	val = readl(tcphy->base + TX_DIG_CTRL_REG_2);
+	val |= BIT(15);
+	writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
+}
+
+static void tcphy_dp_hpd(struct rockchip_typec_phy *tcphy,
+			 u8 mode)
+{
+	/* force hpd */
+	if (mode)
+		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+			     DPTX_HDP_SEL_MASK | DPTX_HDP_SEL);
+	else
+		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+			     DPTX_HDP_SEL_MASK);
+}
+
+static int tcphy_usb3_init(struct rockchip_typec_phy *tcphy)
+{
+	int timeout = 0;
+	int ret, val;
+
+	/*wait TCPHY for pipe ready */
+	while (1) {
+		ret = regmap_read(tcphy->grf_regs,
+				  tcphy->exregs.usb3phy_status0, &val);
+		val >>= tcphy->exregs.usb3phy_status0_shift;
+		if ((val & 0x1) == 0)
+			break;
+
+		timeout++;
+		if (timeout > 1000) {
+			pr_warn("%s wait pipe ready timerout!\n", __func__);
+			break;
+		}
+		usleep_range(10, 20);
+	}
+
+	return 0;
+}
+
+static int tcphy_dp_init(struct rockchip_typec_phy *tcphy)
+{
+	int ret, val;
+
+	ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
+				 val, val & BIT(6), 1000, PHY_MODE_SET_TIMEOUT);
+	if (ret < 0) {
+		dev_err(tcphy->dev, "failed to wait TCPHY for DP ready\n");
+		return -EBUSY;
+	}
+
+	tcphy_dp_aux_calibration(tcphy);
+
+	if (tcphy->mode == MODE_DFP_USB3DP)
+		writel(0xc101, tcphy->base + DP_MODE_CTL);
+	else
+		writel(0x0101, tcphy->base + DP_MODE_CTL);
+
+	ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
+				 val, val & BIT(4), 1000, PHY_MODE_SET_TIMEOUT);
+	if (ret < 0) {
+		dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int tcphy_phy_init(struct rockchip_typec_phy *tcphy)
+{
+	int ret;
+	int timeout = 0;
+
+	ret = clk_prepare_enable(tcphy->clk_core);
+	if (ret) {
+		dev_err(tcphy->dev, "Failed to prepare_enable core clock\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(tcphy->clk_ref);
+	if (ret) {
+		dev_err(tcphy->dev, "Failed to prepare_enable ref clock\n");
+		return ret;
+	}
+
+	/* select external psm clock */
+	regmap_write(tcphy->grf_regs, tcphy->exregs.usb3phy_con2,
+		     BIT(14) | BIT(30));
+	regmap_write(tcphy->grf_regs, tcphy->exregs.usb3phy_con0, BIT(19));
+
+	reset_control_assert(tcphy->phy_rst);
+	reset_control_assert(tcphy->pipe_rst);
+	reset_control_assert(tcphy->uphy_rst);
+
+	if (tcphy->num == TYPEC_PHY0)
+		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+			     UPHY_DP_SEL_MASK);
+	else
+		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+			     UPHY_DP_SEL_MASK | UPHY_DP_SEL);
+
+	reset_control_deassert(tcphy->uphy_rst);
+
+	tcphy_cfg_flip_set(tcphy);
+
+	tcphy_cfg_pin_assign(tcphy);
+
+	if (tcphy->mode == MODE_DFP_USB3DP)
+		writel(0xc104, tcphy->base + DP_MODE_CTL);
+	else if ((tcphy->mode == MODE_DFP_DPONLY) ||
+		 (tcphy->mode == MODE_DFP_USB2DP))
+		writel(0x0104, tcphy->base + DP_MODE_CTL);
+
+	reset_control_deassert(tcphy->phy_rst);
+
+	while (!(readl(tcphy->base + PMA_CMN_CTRL1) & 1)) {
+		timeout++;
+		if (timeout > 1000)
+			break;
+		usleep_range(10, 20);
+	}
+
+	reset_control_deassert(tcphy->pipe_rst);
+
+	return 0;
+}
+
+static int tcphy_phy_deinit(struct rockchip_typec_phy *tcphy)
+{
+	clk_disable_unprepare(tcphy->clk_core);
+	clk_disable_unprepare(tcphy->clk_ref);
+
+	return 0;
+}
+
+int tcphy_register_notifier(struct phy *_phy, struct notifier_block *nb)
+{
+	struct rockchip_typec_phy *tcphy = phy_get_drvdata(_phy);
+
+	return atomic_notifier_chain_register(&tcphy->notifier, nb);
+}
+
+void tcphy_unregister_notifier(struct phy *_phy,
+			       struct notifier_block *nb)
+{
+	struct rockchip_typec_phy *tcphy = phy_get_drvdata(_phy);
+
+	atomic_notifier_chain_unregister(&tcphy->notifier, nb);
+}
+
+void tcphy_notifier_call_chain(struct rockchip_typec_phy *x,
+			       unsigned long val, void *v)
+{
+	atomic_notifier_call_chain(&x->notifier, val, v);
+}
+EXPORT_SYMBOL_GPL(tcphy_notifier_call_chain);
+
+static int tcphy_pd_event(struct notifier_block *nb,
+			  unsigned long event, void *priv)
+{
+	struct rockchip_typec_phy *tcphy;
+	int value = *(int *)priv;
+	u8 is_dp, dfp;
+
+	tcphy = container_of(nb, struct rockchip_typec_phy, event_nb);
+	if (IS_ERR_OR_NULL(tcphy)) {
+		pr_err("initialization issue");
+		return -1;
+	}
+
+	tcphy->flip = GET_FLIP(value);
+	dfp = GET_DFP(value);
+	is_dp = GET_DP(value);
+	tcphy->map = GET_PIN_MAP(value);
+
+	if (event == 0) {
+		if (tcphy->mode == MODE_DISCONNECT)
+			return 0;
+		tcphy->mode = MODE_DISCONNECT;
+	} else if (is_dp) {
+		if (tcphy->map & (PIN_MAP_B | PIN_MAP_D | PIN_MAP_F))
+			tcphy->mode = MODE_DFP_USB3DP;
+		else
+			tcphy->mode = MODE_DFP_DPONLY;
+	} else if (dfp) {
+		tcphy->mode = MODE_DFP_USBONLY;
+	} else {
+		tcphy->mode = MODE_UFP;
+	}
+
+	schedule_delayed_work_on(0, &tcphy->event_wq, 0);
+
+	return 0;
+}
+
+static void tcphy_event_wq(struct work_struct *work)
+{
+	struct rockchip_typec_phy *tcphy;
+
+	tcphy = container_of(work, struct rockchip_typec_phy, event_wq.work);
+	if (IS_ERR_OR_NULL(tcphy)) {
+		pr_err("initialization issue");
+		return;
+	}
+
+	switch (tcphy->mode) {
+	case MODE_DISCONNECT:
+		/* phy enter low power mode */
+		tcphy_phy_deinit(tcphy);
+		tcphy_dp_hpd(tcphy, 0);
+		break;
+	case MODE_UFP:
+		tcphy_phy_init(tcphy);
+		tcphy_usb3_init(tcphy);
+		tcphy_dp_hpd(tcphy, 0);
+		break;
+	case MODE_DFP_USBONLY:
+		tcphy_phy_init(tcphy);
+		tcphy_usb3_init(tcphy);
+		tcphy_dp_hpd(tcphy, 0);
+		break;
+	case MODE_DFP_DPONLY:
+	case MODE_DFP_USB2DP:
+		tcphy_phy_init(tcphy);
+		tcphy_dp_init(tcphy);
+		tcphy_dp_hpd(tcphy, 1);
+		break;
+	case MODE_DFP_USB3DP:
+		tcphy_phy_init(tcphy);
+		tcphy_usb3_init(tcphy);
+		tcphy_dp_init(tcphy);
+		tcphy_dp_hpd(tcphy, 1);
+		break;
+	}
+}
+
+int tcphy_parse_reg(struct rockchip_typec_phy *tcphy, struct device *dev)
+{
+	struct tcphy_grf_reg *exregs = &tcphy->exregs;
+	struct device_node *np = dev->of_node;
+	u32 len = 0, array[3];
+	int ret = 0;
+
+	PARSE_GRF_REG(con0);
+	PARSE_GRF_REG(con1);
+	PARSE_GRF_REG(con2);
+	PARSE_GRF_REG(status0);
+	PARSE_GRF_REG(status1);
+	return ret;
+}
+
+static int rockchip_typec_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rockchip_typec_phy *tcphy;
+	struct resource *res;
+	struct phy_provider *phy_provider;
+
+	tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
+	if (!tcphy)
+		return -ENOMEM;
+
+	tcphy->dev = dev;
+	platform_set_drvdata(pdev, tcphy);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	tcphy->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(tcphy->base)) {
+		dev_err(dev, "failed to remap phy regs\n");
+		return PTR_ERR(tcphy->base);
+	}
+	tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node,
+							"rockchip,grf");
+	if (IS_ERR(tcphy->grf_regs)) {
+		dev_err(dev, "%s: could not find grf dt node\n", __func__);
+		return PTR_ERR(tcphy->grf_regs);
+	}
+
+	tcphy->clk_core = of_clk_get_by_name(dev->of_node, "tcpdcore");
+	if (IS_ERR(tcphy->clk_core)) {
+		dev_err(dev, "%s: could not get uphy core clock\n", __func__);
+		tcphy->clk_core = NULL;
+	}
+
+	tcphy->clk_ref = of_clk_get_by_name(dev->of_node, "tcpdphy_ref");
+	if (IS_ERR(tcphy->clk_core)) {
+		dev_err(dev, "%s: could not get uphy ref clock\n", __func__);
+		tcphy->clk_core = NULL;
+	}
+
+	tcphy->phy_rst = devm_reset_control_get(dev, "tcphy_rst");
+	if (IS_ERR(tcphy->phy_rst)) {
+		dev_err(dev, "no phy_rst reset control found\n");
+		return PTR_ERR(tcphy->phy_rst);
+	}
+
+	tcphy->pipe_rst = devm_reset_control_get(dev, "tcphy_pipe_rst");
+	if (IS_ERR(tcphy->pipe_rst)) {
+		dev_err(dev, "no pipe_rst reset control found\n");
+		return PTR_ERR(tcphy->pipe_rst);
+	}
+
+	tcphy->uphy_rst = devm_reset_control_get(dev, "uphy_tcphy_rst");
+	if (IS_ERR(tcphy->uphy_rst)) {
+		dev_err(dev, "no uphy_rst reset control found\n");
+		return PTR_ERR(tcphy->uphy_rst);
+	}
+
+	tcphy_parse_reg(tcphy, dev);
+	tcphy->mode = MODE_DISCONNECT;
+
+	tcphy->phy = devm_phy_create(dev, NULL, NULL);
+
+	phy_set_drvdata(tcphy->phy, tcphy);
+
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+	/* register notifier for PD event */
+	ATOMIC_INIT_NOTIFIER_HEAD(&tcphy->notifier);
+	tcphy->event_nb.notifier_call = tcphy_pd_event;
+	INIT_DELAYED_WORK(&tcphy->event_wq, tcphy_event_wq);
+	tcphy_register_notifier(tcphy->phy, &tcphy->event_nb);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static int rockchip_typec_phy_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct of_device_id rockchip_typec_phy_dt_ids[] = {
+	{ .compatible = "rockchip,rk3399-typec-phy", },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids);
+
+static struct platform_driver rockchip_typec_phy_driver = {
+	.probe		= rockchip_typec_phy_probe,
+	.remove		= rockchip_typec_phy_remove,
+	.driver		= {
+		.name	= "rockchip-typec-phy",
+		.of_match_table = rockchip_typec_phy_dt_ids,
+	},
+};
+
+module_platform_driver(rockchip_typec_phy_driver);
+
+MODULE_AUTHOR("Kever Yang<kever.yang at rock-chips.com>");
+MODULE_AUTHOR("Chris Zhong<zyw at rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip USB TYPE-C PHY driver");
+MODULE_LICENSE("GPL v2");
-- 
2.6.3



From zyw at rock-chips.com  Thu May 26 23:02:15 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 14:02:15 +0800
Subject: [PATCH 2/6] Documentation: bindings: add dt doc for Rockchip USB
 Type-C PHY
In-Reply-To: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464328939-8073-3-git-send-email-zyw@rock-chips.com>

This patch adds a binding that describes the Rockchip USB Type-C PHY
for rk3399.

Signed-off-by: Chris Zhong <zyw at rock-chips.com>
---

 .../devicetree/bindings/phy/phy-rockchip-typec.txt | 55 ++++++++++++++++++++++
 1 file changed, 55 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt

diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
new file mode 100644
index 0000000..402f667
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
@@ -0,0 +1,55 @@
+ROCKCHIP type-c PHY
+
+Required properties:
+ - compatible: should be "rockchip,rk3399-typec-phy"
+ - reg : Address and length of the usb phy control register set
+ - rockchip,grf : phandle to the syscon managing the "general
+   register files"
+ - clocks : phandle + clock specifier for the phy clocks
+ - clock-names: string, clock name, must be "tcpdcore", "tcpdphy_ref";
+ - resets : a list of phandle + reset specifier pairs
+ - reset-names : string reset name, must be:
+		 "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst"
+ - #phy-cells: Must be 0.  See ./phy-bindings.txt for details.
+ - rockchip,usb3phy*: phy registers embed in grf
+
+Example:
+	tcphy0: phy at ff7c0000 {
+		compatible = "rockchip,rk3399-typec-phy";
+		reg = <0x0 0xff7c0000 0x0 0x40000>;
+		#phy-cells = <0>;
+		rockchip,grf = <&grf>;
+		clocks = <&cru SCLK_UPHY0_TCPDCORE>,
+			 <&cru SCLK_UPHY0_TCPDPHY_REF>;
+		clock-names = "tcpdcore", "tcpdphy_ref";
+		resets = <&cru SRST_UPHY0>,
+			 <&cru SRST_UPHY0_PIPE_L00>,
+			 <&cru SRST_P_UPHY0_TCPHY>;
+		reset-names = "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst";
+		rockchip,usb3phy_con0 = <0x0e580 0 16>;
+		rockchip,usb3phy_con1 = <0x0e584 0 16>;
+		rockchip,usb3phy_con2 = <0x0e588 0 16>;
+		rockchip,usb3phy_status0 = <0x0e5c0 0 13>;
+		rockchip,usb3phy_status1 = <0x0e5c4 0 12>;
+		status = "disabled";
+	};
+
+	tcphy1: phy at ff800000 {
+		compatible = "rockchip,rk3399-typec-phy";
+		reg = <0x0 0xff800000 0x0 0x40000>;
+		#phy-cells = <0>;
+		rockchip,grf = <&grf>;
+		clocks = <&cru SCLK_UPHY1_TCPDCORE>,
+			 <&cru SCLK_UPHY1_TCPDPHY_REF>;
+		clock-names = "tcpdcore", "tcpdphy_ref";
+		resets = <&cru SRST_UPHY1>,
+		         <&cru SRST_UPHY1_PIPE_L00>,
+			 <&cru SRST_P_UPHY1_TCPHY>;
+		reset-names = "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst";
+		rockchip,usb3phy_con0 = <0x0e58c 0 16>;
+		rockchip,usb3phy_con1 = <0x0e590 0 16>;
+		rockchip,usb3phy_con2 = <0x0e594 0 16>;
+		rockchip,usb3phy_status0 = <0x0e5c0 16 13>;
+		rockchip,usb3phy_status1 = <0x0e5c4 16 12>;
+		status = "disabled";
+	};
-- 
2.6.3



From zyw at rock-chips.com  Thu May 26 23:02:16 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 14:02:16 +0800
Subject: [PATCH 3/6] drm/rockchip: vop: add cdn DP support for rk3399
In-Reply-To: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464328939-8073-4-git-send-email-zyw@rock-chips.com>

Add support for cdn DP controller which is embedded in the rk3399
SoCs. The DP is compliant with DisplayPort Specification,
Version 1.3, This IP is compatible with the rockchip type-c PHY IP.
There is a uCPU in DP controller, it need a firmware to work,
please put the firmware file to /lib/firmware/cdn/dptx.bin. The
uCPU in charge of aux communication and link training, the host use
mailbox to communicate with the ucpu.
The dclk pin_pol of vop must not be invert for DP.

Signed-off-by: Chris Zhong <zyw at rock-chips.com>
---

 drivers/gpu/drm/rockchip/Kconfig            |   9 +
 drivers/gpu/drm/rockchip/Makefile           |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c      | 620 +++++++++++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-core.h      |  95 ++++
 drivers/gpu/drm/rockchip/cdn-dp-reg.c       | 730 ++++++++++++++++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-reg.h       | 404 +++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c |   9 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   2 +
 include/sound/cdn-dp-audio.h                |  51 ++
 10 files changed, 1922 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.h
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.h
 create mode 100644 include/sound/cdn-dp-audio.h

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index d30bdc3..20da9a8 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -25,6 +25,15 @@ config ROCKCHIP_ANALOGIX_DP
 	  for the Analogix Core DP driver. If you want to enable DP
 	  on RK3288 based SoC, you should selet this option.
 
+config ROCKCHIP_CDN_DP
+        tristate "Rockchip cdn DP"
+        depends on DRM_ROCKCHIP
+        help
+	  This selects support for Rockchip SoC specific extensions
+	  for the cdn Dp driver. If you want to enable Dp on
+	  RK3399 based SoC, you should selet this
+	  option.
+
 config ROCKCHIP_DW_HDMI
         tristate "Rockchip specific extensions for Synopsys DW HDMI"
         depends on DRM_ROCKCHIP
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..abdecd5 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -7,6 +7,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
+obj-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
 obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
 obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
 obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
new file mode 100644
index 0000000..fdf99f5
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -0,0 +1,620 @@
+/*
+ * cdn dp controller core driver
+ *
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+
+#include <linux/component.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+#include <linux/mfd/syscon.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-rockchip-typec.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+#include <sound/cdn-dp-audio.h>
+
+#include "rockchip_drm_vop.h"
+#include "cdn-dp-reg.h"
+#include "cdn-dp-core.h"
+
+#define connector_to_dp(c) \
+		container_of(c, struct cdn_dp_device, connector)
+
+#define encoder_to_dp(c) \
+		container_of(c, struct cdn_dp_device, encoder)
+
+/* dp grf register offset */
+#define DP_VOP_SEL		0x6224
+#define DP_SEL_VOP_LIT		BIT(12)
+
+static int cdn_dp_clk_enable(struct cdn_dp_device *dp)
+{
+	int ret = 0;
+	int clk_rate = 200000000;
+
+	ret = clk_prepare_enable(dp->pclk);
+	if (ret < 0) {
+		dev_err(dp->dev, "cannot enable dp pclk %d\n", ret);
+		goto err_pclk;
+	}
+
+	ret = clk_prepare_enable(dp->core_clk);
+	if (ret < 0) {
+		dev_err(dp->dev, "cannot enable core_clk %d\n", ret);
+		goto err_core_clk;
+	}
+
+	ret = clk_set_rate(dp->core_clk, clk_rate);
+	if (ret < 0) {
+		dev_err(dp->dev, "cannot set dp core clk to %d %d\n",
+			clk_rate, ret);
+		goto err_set_rate;
+	}
+
+	/* notice fw the clk freq value */
+	cdn_dp_set_fw_clk(dp, clk_rate);
+
+	return 0;
+
+err_set_rate:
+	clk_disable_unprepare(dp->core_clk);
+err_core_clk:
+	clk_disable_unprepare(dp->pclk);
+err_pclk:
+	return ret;
+}
+
+static enum drm_connector_status
+cdn_dp_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct cdn_dp_device *dp = connector_to_dp(connector);
+	int ret;
+
+	if (!dp->fw_loaded)
+		return connector_status_unknown;
+
+	ret = cdn_dp_get_hpd_status(dp);
+	if (ret < 0)
+		return connector_status_unknown;
+
+	dp->plugged = ret;
+
+	return ret ? connector_status_connected : connector_status_disconnected;
+}
+
+static void cdn_dp_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs cdn_dp_atomic_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.detect = cdn_dp_connector_detect,
+	.destroy = cdn_dp_connector_destroy,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int cdn_dp_connector_get_modes(struct drm_connector *connector)
+{
+	struct cdn_dp_device *dp = connector_to_dp(connector);
+	struct edid *edid;
+	int ret;
+
+	if (!dp->fw_loaded)
+		return 0;
+
+	ret = cdn_dp_set_host_cap(dp);
+	if (ret) {
+		dev_err(dp->dev, "set host capabilities failed:%d\n", ret);
+		return ret;
+	}
+
+	edid = drm_do_get_edid(connector, cdn_dp_get_edid_block, dp);
+	if (edid) {
+		dev_dbg(dp->dev, "got edid: width[%d] x height[%d]\n",
+			edid->width_cm, edid->height_cm);
+
+		dp->sink_has_audio = drm_detect_monitor_audio(edid);
+		drm_mode_connector_update_edid_property(connector, edid);
+		drm_add_edid_modes(connector, edid);
+		/* Store the ELD */
+		drm_edid_to_eld(connector, edid);
+		kfree(edid);
+	} else {
+		dev_dbg(dp->dev, "failed to get edid\n");
+	}
+
+	/*
+	 * put the training process here, since the mode_valid need the
+	 * training result to check if the resolution is support.
+	 */
+	ret = cdn_dp_training_start(dp);
+	if (ret) {
+		dev_err(dp->dev, "hw lt err:%d\n", ret);
+		return ret;
+	}
+
+	ret = cdn_dp_get_lt_status(dp);
+	if (ret) {
+		dev_err(dp->dev, "hw lt get status err:%d\n", ret);
+		return ret;
+	}
+
+	dev_dbg(dp->dev, "rate:%d, lanes:%d\n",
+		dp->link.rate, dp->link.num_lanes);
+	return 0;
+}
+
+static struct drm_encoder *
+	cdn_dp_connector_best_encoder(struct drm_connector *connector)
+{
+	struct cdn_dp_device *dp = connector_to_dp(connector);
+
+	return &dp->encoder;
+}
+
+static int cdn_dp_connector_mode_valid(struct drm_connector *connector,
+				       struct drm_display_mode *mode)
+{
+	struct cdn_dp_device *dp = connector_to_dp(connector);
+	struct drm_display_info *display_info = &dp->connector.display_info;
+	long requested = mode->clock * display_info->bpc * 3 / 1000;
+	long actual, rate;
+
+	rate = drm_dp_bw_code_to_link_rate(dp->link.rate);
+	actual = rate * dp->link.num_lanes / 100;
+
+	/* efficiency is about 0.8 */
+	actual = actual * 8 / 10;
+
+	if (requested > actual) {
+		dev_dbg(dp->dev, "requested=%ld, actual=%ld, clock=%d, bpc= %d\n",
+			requested, actual, mode->clock, display_info->bpc);
+		return MODE_H_ILLEGAL;
+	}
+
+	return MODE_OK;
+}
+
+static struct drm_connector_helper_funcs cdn_dp_connector_helper_funcs = {
+	.get_modes = cdn_dp_connector_get_modes,
+	.best_encoder = cdn_dp_connector_best_encoder,
+	.mode_valid = cdn_dp_connector_mode_valid,
+};
+
+static int cdn_dp_commit(struct drm_encoder *encoder)
+{
+	struct cdn_dp_device *dp = encoder_to_dp(encoder);
+	int ret;
+
+	cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
+
+	ret = cdn_dp_config_video(dp);
+	if (ret) {
+		dev_err(dp->dev, "unable to config video\n");
+		return ret;
+	}
+
+	cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID);
+	dp->dpms_mode = DRM_MODE_DPMS_ON;
+
+	return ret;
+}
+
+static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder,
+				    struct drm_display_mode *mode,
+				    struct drm_display_mode *adjusted)
+{
+	struct cdn_dp_device *dp = encoder_to_dp(encoder);
+	struct drm_display_info *display_info = &dp->connector.display_info;
+	struct rockchip_crtc_state *state;
+	struct video_info *video = &dp->video_info;
+	int ret, val;
+
+	switch (display_info->bpc) {
+	case 16:
+	case 12:
+	case 10:
+		video->color_depth = 10;
+		break;
+	case 6:
+		video->color_depth = 6;
+		break;
+	default:
+		video->color_depth = 8;
+		break;
+	}
+
+	video->color_fmt = PXL_RGB;
+
+	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+
+	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
+	if (ret < 0)
+		return;
+
+	state = to_rockchip_crtc_state(encoder->crtc->state);
+	if (ret) {
+		val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16);
+		state->output_mode = ROCKCHIP_OUT_MODE_P888;
+	} else {
+		val = DP_SEL_VOP_LIT << 16;
+		state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
+	}
+	ret = regmap_write(dp->grf, DP_VOP_SEL, val);
+	if (ret != 0)
+		dev_err(dp->dev, "Could not write to GRF: %d\n", ret);
+
+	memcpy(&dp->mode, adjusted, sizeof(*mode));
+}
+
+static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
+{
+	struct cdn_dp_device *dp = encoder_to_dp(encoder);
+
+	if (dp->dpms_mode == DRM_MODE_DPMS_ON)
+		return;
+
+	cdn_dp_commit(encoder);
+}
+
+static void cdn_dp_encoder_disable(struct drm_encoder *encoder)
+{
+	struct cdn_dp_device *dp = encoder_to_dp(encoder);
+
+	if (dp->dpms_mode != DRM_MODE_DPMS_ON)
+		return;
+
+	cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
+
+	dp->dpms_mode = DRM_MODE_DPMS_OFF;
+}
+
+static int
+cdn_dp_encoder_atomic_check(struct drm_encoder *encoder,
+			    struct drm_crtc_state *crtc_state,
+			    struct drm_connector_state *conn_state)
+{
+	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+
+	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
+	s->output_type = DRM_MODE_CONNECTOR_DisplayPort;
+
+	return 0;
+}
+
+static struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = {
+	.mode_set = cdn_dp_encoder_mode_set,
+	.enable = cdn_dp_encoder_enable,
+	.disable = cdn_dp_encoder_disable,
+	.atomic_check = cdn_dp_encoder_atomic_check,
+};
+
+static struct drm_encoder_funcs cdn_dp_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+int cdn_dp_firmware_init(struct cdn_dp_device *dp)
+{
+	int ret;
+	const u32 *iram_data, *dram_data;
+	const struct firmware *fw;
+	const struct cdn_firmware_header *hdr;
+
+	if (dp->fw_loaded)
+		return 0;
+
+	ret = request_firmware(&fw, "cdn/dptx.bin", dp->dev);
+	if (ret < 0) {
+		dev_err(dp->dev, "failed to request firmware %d\n", ret);
+		return ret;
+	}
+
+	hdr = (struct cdn_firmware_header *)fw->data;
+	if (fw->size != le32_to_cpu(hdr->size_bytes))
+		return -EINVAL;
+
+	ret = cdn_dp_clk_enable(dp);
+	if (ret < 0) {
+		dev_err(dp->dev, "cannot enable dp clk %d\n", ret);
+		return ret;
+	}
+
+	dp_clock_reset_seq(dp);
+
+	iram_data = (const u32 *)(fw->data + hdr->header_size);
+	dram_data = (const u32 *)(fw->data + hdr->header_size + hdr->iram_size);
+
+	ret = cdn_dp_load_firmware(dp,
+				   iram_data, hdr->iram_size,
+				   dram_data, hdr->dram_size);
+
+	ret = cdn_dp_active(dp, true);
+	if (ret) {
+		dev_err(dp->dev, "active ucpu failed: %d\n", ret);
+		return ret;
+	}
+
+	cdn_dp_event_config(dp);
+
+	return 0;
+}
+
+static int cdn_dp_init(struct cdn_dp_device *dp)
+{
+	struct device *dev = dp->dev;
+	struct device_node *np = dev->of_node;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res;
+
+	dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+	if (IS_ERR(dp->grf)) {
+		dev_err(dev, "cdn-dp needs rockchip,grf property\n");
+		return PTR_ERR(dp->grf);
+	}
+
+	dp->irq = platform_get_irq(pdev, 0);
+	if (dp->irq < 0) {
+		dev_err(dev, "cdn-dp can not get irq\n");
+		return dp->irq;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dp->regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(dp->regs)) {
+		dev_err(dev, "ioremap reg failed\n");
+		return PTR_ERR(dp->regs);
+	}
+
+	dp->core_clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(dp->core_clk)) {
+		dev_err(dev, "cannot get core_clk_dp\n");
+		return PTR_ERR(dp->core_clk);
+	}
+
+	dp->pclk = devm_clk_get(dev, "pclk");
+	if (IS_ERR(dp->pclk)) {
+		dev_err(dev, "cannot get pclk\n");
+		return PTR_ERR(dp->pclk);
+	}
+
+	dp->spdif_clk = devm_clk_get(dev, "spdif");
+	if (IS_ERR(dp->spdif_clk)) {
+		dev_err(dev, "cannot get spdif_clk\n");
+		return PTR_ERR(dp->spdif_clk);
+	}
+
+	dp->dpms_mode = DRM_MODE_DPMS_OFF;
+
+	dev_set_name(dp->dev, "cdn-dp");
+
+	return 0;
+}
+
+static const struct cdn_dp_audio_ops dp_audio_ops = {
+	.audio_startup = cdn_dp_audio_start,
+	.audio_shutdown = cdn_dp_audio_stop,
+	.audio_start = cdn_dp_audio_start,
+	.audio_stop = cdn_dp_audio_stop,
+	.audio_config = cdn_dp_audio_config_set,
+};
+
+static int cdn_dp_pd_event(struct notifier_block *nb,
+			   unsigned long event, void *priv)
+{
+	struct cdn_dp_device *dp;
+	u8 map, is_dp;
+	int value = *(int *)priv;
+
+	dp = container_of(nb, struct cdn_dp_device, event_nb);
+	if (IS_ERR_OR_NULL(dp)) {
+		pr_err("initialization issue");
+		return -1;
+	}
+
+	is_dp = GET_DP(value);
+
+	if (!is_dp)
+		return 0;
+
+	dp->flip = GET_FLIP(value);
+	map = GET_PIN_MAP(value);
+	if (map & (PIN_MAP_B | PIN_MAP_D | PIN_MAP_F))
+		dp->cap_lanes = 2;
+	else
+		dp->cap_lanes = 4;
+
+	schedule_delayed_work_on(0, &dp->event_wq, 100);
+
+	return 0;
+}
+
+static void cdn_dp_pd_event_wq(struct work_struct *work)
+{
+	struct cdn_dp_device *dp;
+
+	dp = container_of(work, struct cdn_dp_device, event_wq.work);
+	if (IS_ERR_OR_NULL(dp)) {
+		pr_err("initialization issue");
+		return;
+	}
+
+	if (cdn_dp_firmware_init(dp))
+		return;
+
+	if ((cdn_dp_get_event(dp) & DPTX_HPD_EVENT) && (dp->drm_dev))
+		drm_helper_hpd_irq_event(dp->drm_dev);
+}
+
+static int cdn_dp_bind(struct device *dev, struct device *master,
+		       void *data)
+{
+	struct cdn_dp_audio_pdata audio_pdata;
+	struct cdn_dp_device *dp = dev_get_drvdata(dev);
+	struct device_node *np = dev->of_node;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	struct drm_device *drm_dev = data;
+	struct phy *phy = devm_of_phy_get_by_index(dev, np, 0);
+	int ret;
+
+	if (IS_ERR(phy))
+		return -EPROBE_DEFER;
+
+	dp->phy = phy;
+
+	ret = cdn_dp_init(dp);
+	if (ret < 0)
+		return ret;
+
+	dp->drm_dev = drm_dev;
+
+	encoder = &dp->encoder;
+
+	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
+							     dev->of_node);
+	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+
+	ret = drm_encoder_init(drm_dev, encoder, &cdn_dp_encoder_funcs,
+			       DRM_MODE_ENCODER_TMDS, NULL);
+	if (ret) {
+		DRM_ERROR("failed to initialize encoder with drm\n");
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs);
+
+	connector = &dp->connector;
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
+	connector->dpms = DRM_MODE_DPMS_OFF;
+
+	ret = drm_connector_init(drm_dev, connector,
+				 &cdn_dp_atomic_connector_funcs,
+				 DRM_MODE_CONNECTOR_DisplayPort);
+	if (ret) {
+		DRM_ERROR("failed to initialize connector with drm\n");
+		goto err_free_encoder;
+	}
+
+	drm_connector_helper_add(connector, &cdn_dp_connector_helper_funcs);
+
+	ret = drm_mode_connector_attach_encoder(connector, encoder);
+	if (ret) {
+		DRM_ERROR("failed to attach connector and encoder\n");
+		goto err_free_connector;
+	}
+
+	audio_pdata.dev = dev,
+	audio_pdata.ops = &dp_audio_ops,
+	audio_pdata.data = dp;
+
+	dp->audio_pdev = platform_device_register_data(
+		dev, "cdn-dp-audio", PLATFORM_DEVID_NONE,
+		&audio_pdata, sizeof(audio_pdata));
+
+	if (IS_ERR(dp->audio_pdev))
+		return PTR_ERR(dp->audio_pdev);
+
+	dp->event_nb.notifier_call = cdn_dp_pd_event;
+	INIT_DELAYED_WORK(&dp->event_wq, cdn_dp_pd_event_wq);
+	tcphy_register_notifier(phy, &dp->event_nb);
+
+	return 0;
+
+err_free_connector:
+	drm_connector_cleanup(connector);
+err_free_encoder:
+	drm_encoder_cleanup(encoder);
+	return ret;
+}
+
+static void cdn_dp_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct cdn_dp_device *dp = dev_get_drvdata(dev);
+	struct drm_encoder *encoder = &dp->encoder;
+
+	platform_device_unregister(dp->audio_pdev);
+	cdn_dp_encoder_disable(encoder);
+	encoder->funcs->destroy(encoder);
+	drm_connector_unregister(&dp->connector);
+	drm_connector_cleanup(&dp->connector);
+	drm_encoder_cleanup(encoder);
+	tcphy_unregister_notifier(dp->phy, &dp->event_nb);
+}
+
+static const struct component_ops cdn_dp_component_ops = {
+	.bind = cdn_dp_bind,
+	.unbind = cdn_dp_unbind,
+};
+
+static int cdn_dp_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cdn_dp_device *dp;
+
+	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
+	if (!dp)
+		return -ENOMEM;
+	dp->dev = dev;
+
+	platform_set_drvdata(pdev, dp);
+
+	return component_add(dev, &cdn_dp_component_ops);
+}
+
+static int cdn_dp_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &cdn_dp_component_ops);
+
+	return 0;
+}
+
+static const struct of_device_id cdn_dp_dt_ids[] = {
+	{.compatible = "rockchip,cdn-dp",},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, cdn_dp_dt_ids);
+
+static struct platform_driver cdn_dp_driver = {
+	.probe = cdn_dp_probe,
+	.remove = cdn_dp_remove,
+	.driver = {
+		   .name = "cdn-dp",
+		   .owner = THIS_MODULE,
+		   .of_match_table = of_match_ptr(cdn_dp_dt_ids),
+	},
+};
+
+module_platform_driver(cdn_dp_driver);
+
+MODULE_AUTHOR("Chris Zhong <zyw at rock-chips.com>");
+MODULE_DESCRIPTION("cdn DP Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
new file mode 100644
index 0000000..99c0123
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ROCKCHIP_EDP_CORE_H
+#define _ROCKCHIP_EDP_CORE_H
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_panel.h>
+#include "rockchip_drm_drv.h"
+#include "cdn-dp-reg.h"
+
+struct video_info {
+	bool h_sync_polarity;
+	bool v_sync_polarity;
+	bool interlaced;
+	int color_depth;
+	enum VIC_PXL_ENCODING_FORMAT color_fmt;
+};
+
+struct cdn_firmware_header {
+	u32 size_bytes; /* size of the entire header+image(s) in bytes */
+	u32 header_size; /* size of just the header in bytes */
+	u32 iram_size; /* size of iram */
+	u32 dram_size; /* size of dram */
+};
+
+struct cdn_dp_device {
+	struct device *dev;
+	struct drm_device *drm_dev;
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+	struct drm_display_mode mode;
+	struct delayed_work hotplug_work;
+	struct platform_device *audio_pdev;
+	bool plugged;
+
+	const struct firmware *fw;	/* cdn dp firmware */
+	unsigned int fw_version;	/* cdn fw version */
+	bool fw_loaded;
+	void __iomem *regs;
+	void __iomem *phy_regs;
+	struct regmap *grf;
+	unsigned int irq;
+	struct clk *core_clk;
+	struct clk *pclk;
+	struct clk *spdif_clk;
+	struct video_info video_info;
+	struct phy *phy;
+	struct notifier_block	event_nb;
+	struct delayed_work	event_wq;
+
+	int cap_lanes;
+	bool flip;
+
+	int dpms_mode;
+	struct drm_dp_link link;
+	bool sink_has_audio;
+};
+
+void dp_clock_reset_seq(struct cdn_dp_device *dp);
+
+void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, int clk);
+int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem,
+			 u32 i_size, const u32 *d_mem, u32 d_size);
+int cdn_dp_active(struct cdn_dp_device *dp, u8 enable);
+int cdn_dp_set_host_cap(struct cdn_dp_device *dp);
+int cdn_dp_event_config(struct cdn_dp_device *dp);
+int cdn_dp_get_event(struct cdn_dp_device *dp);
+int cdn_dp_get_hpd_status(struct cdn_dp_device *dp);
+int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value);
+int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr);
+int cdn_dp_get_edid_block(void *dp, u8 *edid,
+			  unsigned int block, size_t length);
+int cdn_dp_training_start(struct cdn_dp_device *dp);
+int cdn_dp_get_lt_status(struct cdn_dp_device *dp);
+int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active);
+int cdn_dp_config_video(struct cdn_dp_device *dp);
+int cdn_dp_audio_start(void *dp_dev, struct audio_info *audio);
+int cdn_dp_audio_stop(void *dp_dev, struct audio_info *audio);
+int cdn_dp_audio_config_set(void *dp_dev, struct audio_info *audio);
+
+#endif  /* _ROCKCHIP_EDP_CORE_H */
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
new file mode 100644
index 0000000..d6c9bcb
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
@@ -0,0 +1,730 @@
+/*
+ * cdn dp controller register driver
+ *
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/reset.h>
+
+#include <sound/cdn-dp-audio.h>
+
+#include "cdn-dp-core.h"
+#include "cdn-dp-reg.h"
+
+#define FW_ALIVE_TIMEOUT_US		1000000
+#define MAILBOX_TIMEOUT_US		5000000
+
+/* the max size of read buff is 134 */
+static u8 rx_buff[134];
+
+void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, int clk)
+{
+	writel(clk / 1000000, dp->regs + SW_CLK_H);
+}
+
+void dp_clock_reset_seq(struct cdn_dp_device *dp)
+{
+	writel(0xfff, dp->regs + SOURCE_DPTX_CAR);
+	writel(0x7, dp->regs + SOURCE_PHY_CAR);
+	writel(0xf, dp->regs + SOURCE_PKT_CAR);
+	writel(0xff, dp->regs + SOURCE_AIF_CAR);
+	writel(0xf, dp->regs + SOURCE_CIPHER_CAR);
+	writel(0x3, dp->regs + SOURCE_CRYPTO_CAR);
+	writel(0, dp->regs + APB_INT_MASK);
+}
+
+static u8 cdn_dp_mailbox_read(struct cdn_dp_device *dp)
+{
+	int val, ret;
+
+	if (!dp->fw_loaded)
+		return 0;
+
+	ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR,
+				 val, !val, 1000, MAILBOX_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(dp->dev, "failed to wait mailbox response\n");
+		return 0;
+	}
+
+	return readl(dp->regs + MAILBOX0_RD_DATA) & 0xff;
+}
+
+static void cdp_dp_mailbox_write(struct cdn_dp_device *dp, u8 val)
+{
+	int ret, full;
+
+	if (!dp->fw_loaded)
+		return;
+
+	ret = readx_poll_timeout(readl, dp->regs + MAILBOX_FULL_ADDR,
+				 full, !full, 1000, MAILBOX_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(dp->dev, "mailbox is full\n");
+		return;
+	}
+
+	writel(val, dp->regs + MAILBOX0_WR_DATA);
+}
+
+/* return the size of message */
+int cdn_dp_mailbox_response(struct cdn_dp_device *dp, u8 module_id,
+			    u8 opcode, u8 **message)
+{
+	int size, i = 0;
+
+	memset(rx_buff, 0, 4);
+
+	while (i < sizeof(rx_buff)) {
+		if (i < sizeof(rx_buff))
+			rx_buff[i++] = cdn_dp_mailbox_read(dp);
+
+		size = ((rx_buff[2] << 8) | rx_buff[3]) + 4;
+		if (i >= size)
+			break;
+	}
+
+	if ((opcode != rx_buff[0]) || (module_id != rx_buff[1]))
+		return -EINVAL;
+
+	size = (rx_buff[2] << 8) | rx_buff[3];
+
+	*message = &rx_buff[4];
+
+	return size;
+}
+
+int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id, u8 opcode,
+			u16 size, u8 *message)
+{
+	cdp_dp_mailbox_write(dp, opcode);
+	cdp_dp_mailbox_write(dp, module_id);
+	cdp_dp_mailbox_write(dp, size >> 8);
+	cdp_dp_mailbox_write(dp, size & 0xff);
+
+	while (size--)
+		cdp_dp_mailbox_write(dp, *message++);
+
+	return 0;
+}
+
+int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem,
+			 u32 i_size, const u32 *d_mem, u32 d_size)
+{
+	int i, reg, ret;
+
+	/* reset ucpu before load firmware*/
+	writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET,
+	       dp->regs + APB_CTRL);
+
+	for (i = 0; i < i_size; i += 4)
+		writel(*i_mem++, dp->regs + ADDR_IMEM + i);
+
+	for (i = 0; i < d_size; i += 4)
+		writel(*d_mem++, dp->regs + ADDR_DMEM + i);
+
+	/* un-reset ucpu */
+	writel(0, dp->regs + APB_CTRL);
+
+	/* check the keep alive register to make sure fw working */
+	ret = readx_poll_timeout(readl, dp->regs + KEEP_ALIVE,
+				 reg, reg, 2000, FW_ALIVE_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(dp->dev, "failed to loaded the FW reg = %x\n", reg);
+		return -EINVAL;
+	}
+
+	reg = readl(dp->regs + VER_L) & 0xff;
+	dp->fw_version = reg;
+	reg = readl(dp->regs + VER_H) & 0xff;
+	dp->fw_version |= reg << 8;
+	reg = readl(dp->regs + VER_LIB_L_ADDR) & 0xff;
+	dp->fw_version |= reg << 16;
+	reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff;
+	dp->fw_version |= reg << 24;
+
+	dp->fw_loaded = 1;
+
+	return 0;
+}
+
+int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val)
+{
+	u8 msg[6];
+
+	msg[0] = (addr >> 8) & 0xff;
+	msg[1] = addr & 0xff;
+	msg[2] = (val >> 24) & 0xff;
+	msg[3] = (val >> 16) & 0xff;
+	msg[4] = (val >> 8) & 0xff;
+	msg[5] = val & 0xff;
+	return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_REGISTER,
+				   ARRAY_SIZE(msg), msg);
+}
+
+int cdn_dp_reg_read(struct cdn_dp_device *dp, u16 addr)
+{
+	u8 msg[2], *reg = NULL;
+	u16 size;
+
+	msg[0] = (addr >> 8) & 0xff;
+	msg[1] = addr & 0xff;
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_REGISTER,
+			    ARRAY_SIZE(msg), msg);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_READ_REGISTER, &reg);
+	if (size != 6)
+		return -EINVAL;
+
+	if ((msg[0] == reg[0]) && (msg[1] == reg[1]))
+		return (reg[2] << 24) | (reg[3] << 16) | (reg[4] << 8) | reg[5];
+
+	return -EINVAL;
+}
+
+int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr, u8 start_bit,
+			 u8 bits_no, u32 val)
+{
+	u8 field[8];
+
+	field[0] = (addr >> 8) & 0xff;
+	field[1] = addr & 0xff;
+	field[2] = start_bit;
+	field[3] = bits_no;
+	field[4] = (val >> 24) & 0xff;
+	field[5] = (val >> 16) & 0xff;
+	field[6] = (val >> 8) & 0xff;
+	field[7] = val & 0xff;
+
+	return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_FIELD,
+			    sizeof(field), field);
+}
+
+int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value)
+{
+	u8 msg[6], *reg = NULL;
+	u16 size;
+
+	msg[0] = 0;
+	msg[1] = 1;
+	msg[2] = (addr >> 16) & 0xff;
+	msg[3] = (addr >> 8) & 0xff;
+	msg[4] = addr & 0xff;
+	msg[5] = value;
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD,
+			    ARRAY_SIZE(msg), msg);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_WRITE_DPCD, &reg);
+	if (size != 5)
+		return -EINVAL;
+
+	if ((msg[2] == reg[2]) && (msg[3] == reg[3]) && (msg[4] == reg[4]))
+		return 0;
+
+	return -EINVAL;
+}
+
+int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr)
+{
+	u8 msg[5], *reg = NULL;
+	u16 size;
+
+	msg[0] = 0;
+	msg[1] = 1;
+	msg[2] = (addr >> 16) & 0xff;
+	msg[3] = (addr >> 8) & 0xff;
+	msg[4] = addr & 0xff;
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_DPCD,
+			    ARRAY_SIZE(msg), msg);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_READ_DPCD, &reg);
+	if (size != 6)
+		return -EINVAL;
+
+	if ((msg[2] == reg[2]) && (msg[3] == reg[3]) && (msg[4] == reg[4]))
+		return reg[5];
+
+	return -EINVAL;
+}
+
+int cdn_dp_active(struct cdn_dp_device *dp, u8 enable)
+{
+	u8 active = enable ? 1 : 0;
+	u8 *resp = NULL;
+	int size;
+
+	/* set firmware status, 1: avtive; 0: standby */
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_GENERAL, GENERAL_MAIN_CONTROL,
+			    1, &active);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_GENERAL,
+				       GENERAL_MAIN_CONTROL, &resp);
+	if (size != 1)
+		return -EINVAL;
+
+	return *resp ? 0 : -EINVAL;
+}
+
+int cdn_dp_set_host_cap(struct cdn_dp_device *dp)
+{
+	u8 msg[8];
+
+	msg[0] = DP_LINK_BW_5_4;
+	msg[1] = dp->cap_lanes;
+	msg[2] = VOLTAGE_LEVEL_2;
+	msg[3] = PRE_EMPHASIS_LEVEL_3;
+	msg[4] = PRBS7 | D10_2 | TRAINING_PTN1 | TRAINING_PTN2;
+	msg[5] = FAST_LT_NOT_SUPPORT;
+	msg[6] = LANE_MAPPING_NORMAL;
+	msg[7] = ENHANCED;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX,
+			    DPTX_SET_HOST_CAPABILITIES,
+			    ARRAY_SIZE(msg), msg);
+
+	cdn_dp_reg_write(dp, DP_AUX_SWAP_INVERSION_CONTROL, AUX_HOST_INVERT);
+
+	return 0;
+}
+
+int cdn_dp_event_config(struct cdn_dp_device *dp)
+{
+	u8 msg[5];
+
+	msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING;
+
+	return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_ENABLE_EVENT,
+				    ARRAY_SIZE(msg), msg);
+}
+
+int cdn_dp_get_event(struct cdn_dp_device *dp)
+{
+	return readl(dp->regs + SW_EVENTS0);
+}
+
+int cdn_dp_get_hpd_status(struct cdn_dp_device *dp)
+{
+	u8 *status = NULL;
+	int size;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_HPD_STATE,
+			    0, NULL);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_HPD_STATE, &status);
+	if (size != 1)
+		return -EINVAL;
+
+	return *status;
+}
+
+int cdn_dp_get_edid_block(void *data, u8 *edid,
+			  unsigned int block, size_t length)
+{
+	struct cdn_dp_device *dp = data;
+	int size;
+	u8 msg[2], *reg = NULL;
+
+	if (length != EDID_BLOCK_SIZE)
+		return -EINVAL;
+
+	msg[0] = block / 2;
+	msg[1] = block % 2;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_GET_EDID,
+			    2, msg);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_GET_EDID, &reg);
+
+	if (size != EDID_DATA + EDID_BLOCK_SIZE) {
+		dev_err(dp->dev, "read edid failed\n");
+		return -EINVAL;
+	}
+
+	if ((reg[EDID_LENGTH_BYTE] != EDID_BLOCK_SIZE) ||
+	    (reg[EDID_SEGMENT_BUMBER] != block / 2)) {
+		dev_err(dp->dev, "edid block size err\n");
+		return -EINVAL;
+	}
+
+	memcpy(edid, &reg[EDID_DATA], EDID_BLOCK_SIZE);
+
+	return 0;
+}
+
+int cdn_dp_training_start(struct cdn_dp_device *dp)
+{
+	int size;
+	u8 msg, *event = NULL;
+	unsigned long timeout;
+
+	msg = LINK_TRAINING_RUN;
+
+	/* start training */
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_TRAINING_CONTROL,
+			    1, &msg);
+
+	/* the whole training should finish in 500ms */
+	timeout = jiffies + msecs_to_jiffies(500);
+	while (1) {
+		msleep(20);
+		cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_EVENT,
+				    0, NULL);
+
+		size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+					       DPTX_READ_EVENT, &event);
+		if (size != 2)
+			return -EINVAL;
+
+		if (event[1] & EQ_PHASE_FINISHED)
+			break;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+int cdn_dp_get_lt_status(struct cdn_dp_device *dp)
+{
+	u8 *status = NULL;
+	int size;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT,
+			    0, NULL);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_READ_LINK_STAT, &status);
+
+	if (size != 10)
+		return -EINVAL;
+
+	dp->link.rate = status[0];
+	dp->link.num_lanes = status[1];
+
+	return 0;
+}
+
+int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active)
+{
+	u8 msg;
+
+	msg = !!active;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO,
+			    1, &msg);
+
+	return 0;
+}
+
+int cdn_dp_set_audio_status(struct cdn_dp_device *dp, int active)
+{
+	u8 msg;
+
+	msg = !!active;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_SET_AUDIO,
+			    1, &msg);
+
+	return 0;
+}
+
+static int cdn_dp_get_msa_misc(struct video_info *video,
+			       struct drm_display_mode *mode)
+{
+	u8 val0, val1;
+	u32 msa_misc;
+
+	switch (video->color_fmt) {
+	case PXL_RGB:
+	case Y_ONLY:
+		val0 = 0;
+		break;
+	case YCBCR_4_4_4:
+		val0 = 6;
+		break;
+	case YCBCR_4_2_2:
+		val0 = 5;
+		break;
+	case YCBCR_4_2_0:
+		val0 = 5;
+		break;
+	};
+
+	switch (video->color_depth) {
+	case 6:
+		val1 = 0;
+		break;
+	case 8:
+		val1 = 1;
+		break;
+	case 10:
+		val1 = 2;
+		break;
+	case 12:
+		val1 = 3;
+		break;
+	case 16:
+		val1 = 4;
+		break;
+	};
+
+	msa_misc = 2 * val0 + 32 * val1 +
+		   ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0);
+
+	return msa_misc;
+}
+
+int cdn_dp_config_video(struct cdn_dp_device *dp)
+{
+	struct video_info *video = &dp->video_info;
+	struct drm_display_mode *mode = &dp->mode;
+	u32 val, link_rate;
+	u8 bit_per_pix;
+
+	bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ?
+		      (video->color_depth * 2) : (video->color_depth * 3);
+
+	val = VIF_BYPASS_INTERLACE;
+
+	cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, val);
+
+	cdn_dp_reg_write(dp, HSYNC2VSYNC_POL_CTRL, 0);
+
+	link_rate = drm_dp_bw_code_to_link_rate(dp->link.rate) / 1000;
+
+	val = TU_SIZE * mode->clock * bit_per_pix;
+	val /= dp->link.num_lanes * link_rate * 8 * 1000;
+	/* FIXME: need add 1 to symbols 4K display */
+	if (mode->clock > 500000)
+		val += 1;
+
+	val += TU_SIZE << 8;
+
+	cdn_dp_reg_write(dp, DP_FRAMER_TU, val);
+
+	switch (video->color_depth) {
+	case 6:
+		val = BCS_6;
+		break;
+	case 8:
+		val = BCS_8;
+		break;
+	case 10:
+		val = BCS_10;
+		break;
+	case 12:
+		val = BCS_12;
+		break;
+	case 16:
+		val = BCS_16;
+		break;
+	};
+
+	val += video->color_fmt << 8;
+	cdn_dp_reg_write(dp, DP_FRAMER_PXL_REPR, val);
+
+	val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0;
+	val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0;
+	cdn_dp_reg_write(dp, DP_FRAMER_SP, val);
+
+	val = (mode->hsync_start - mode->hdisplay) << 16;
+	val |= mode->htotal - mode->hsync_end;
+	cdn_dp_reg_write(dp, DP_FRONT_BACK_PORCH, val);
+
+	val = mode->hdisplay * bit_per_pix / 8;
+	cdn_dp_reg_write(dp, DP_BYTE_COUNT, val);
+
+	val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16);
+	cdn_dp_reg_write(dp, MSA_HORIZONTAL_0, val);
+
+	val = mode->hsync_end - mode->hsync_start;
+	val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15);
+	cdn_dp_reg_write(dp, MSA_HORIZONTAL_1, val);
+
+	val = mode->vtotal;
+	val |= ((mode->vtotal - mode->vsync_start) << 16);
+
+	cdn_dp_reg_write(dp, MSA_VERTICAL_0, val);
+
+	val = mode->vsync_end - mode->vsync_start;
+	val |= mode->vdisplay << 16;
+	val |= (video->v_sync_polarity << 15);
+	cdn_dp_reg_write(dp, MSA_VERTICAL_1, val);
+
+	val = cdn_dp_get_msa_misc(video, mode);
+	cdn_dp_reg_write(dp, MSA_MISC, val);
+
+	cdn_dp_reg_write(dp, STREAM_CONFIG, 1);
+
+	val = mode->hsync_end - mode->hsync_start;
+	val |= (mode->hdisplay << 16);
+	cdn_dp_reg_write(dp, DP_HORIZONTAL, val);
+
+	val = mode->vtotal;
+	val -= (mode->vtotal - mode->vdisplay);
+	val |= (mode->vtotal - mode->vsync_start) << 16;
+
+	cdn_dp_reg_write(dp, DP_VERTICAL_0, val);
+
+	val = mode->vtotal;
+	cdn_dp_reg_write(dp, DP_VERTICAL_1, val);
+
+	val =  0;
+	cdn_dp_reg_write_bit(dp, DP_VB_ID, 2, 1, val);
+
+	return 0;
+}
+
+int cdn_dp_audio_start(void *dp_dev, struct audio_info *audio)
+{
+	struct cdn_dp_device *dp = (struct cdn_dp_device *)dp_dev;
+
+	if (audio->type == TYPE_SPDIF) {
+		clk_prepare_enable(dp->spdif_clk);
+		clk_set_rate(dp->spdif_clk, 400000000);
+	}
+
+	return cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN(1));
+}
+
+int cdn_dp_audio_stop(void *dp_dev, struct audio_info *audio)
+{
+	struct cdn_dp_device *dp = (struct cdn_dp_device *)dp_dev;
+
+	cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN(0));
+
+	if (audio->type == TYPE_SPDIF)
+		clk_disable_unprepare(dp->spdif_clk);
+
+	return 0;
+}
+
+int cdn_dp_audio_config_set(void *dp_dev, struct audio_info *audio)
+{
+	struct cdn_dp_device *dp = (struct cdn_dp_device *)dp_dev;
+	int lanes_param, i2s_port_en_val, val, i;
+
+	if ((audio->channels == 2) && (dp->link.num_lanes == 1))
+		lanes_param = 1;
+	else if (audio->channels == 2)
+		lanes_param = 3;
+	else
+		lanes_param = 0;
+
+	if (audio->channels == 2)
+		i2s_port_en_val = 1;
+	else if (audio->channels == 4)
+		i2s_port_en_val = 3;
+	else
+		i2s_port_en_val = 0xf;
+
+	cdn_dp_reg_write(dp, CM_LANE_CTRL, 0x8000);
+
+	cdn_dp_reg_write(dp, CM_CTRL, 0);
+
+	if (audio->type == TYPE_I2S) {
+		writel(0x0, dp->regs + SPDIF_CTRL_ADDR);
+
+		writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL);
+
+		val = audio->channels - 1;
+		val |= (audio->channels / 2 - 1) << 5;
+		val |= BIT(8);
+		val |= lanes_param << 11;
+		writel(val, dp->regs + SMPL2PKT_CNFG);
+
+		if (audio->word_length == 16)
+			val = 0;
+		else if (audio->word_length == 24)
+			val = 1 << 9;
+		else
+			val = 2 << 9;
+
+		val |= (audio->channels - 1) << 2;
+		val |= i2s_port_en_val << 17;
+		val |= 2 << 11;
+		writel(val, dp->regs + AUDIO_SRC_CNFG);
+
+		for (i = 0; i < (audio->channels + 1) / 2; i++) {
+			if (audio->word_length == 16)
+				val = (0x08 << 8) | (0x08 << 20);
+			else if (audio->word_length == 24)
+				val = (0x0b << 8) | (0x0b << 20);
+
+			val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
+			writel(val, dp->regs + STTS_BIT_CH(i));
+		}
+
+		switch (audio->freq) {
+		case 32000:
+			val = SAMPLING_FREQ(3) |
+			      ORIGINAL_SAMP_FREQ(0xc);
+			break;
+		case 44100:
+			val = SAMPLING_FREQ(0) |
+			      ORIGINAL_SAMP_FREQ(0xf);
+			break;
+		case 48000:
+			val = SAMPLING_FREQ(2) |
+			      ORIGINAL_SAMP_FREQ(0xd);
+			break;
+		case 88200:
+			val = SAMPLING_FREQ(8) |
+			      ORIGINAL_SAMP_FREQ(0x7);
+			break;
+		case 96000:
+			val = SAMPLING_FREQ(0xa) |
+			      ORIGINAL_SAMP_FREQ(5);
+			break;
+		case 176400:
+			val = SAMPLING_FREQ(0xc) |
+			      ORIGINAL_SAMP_FREQ(3);
+			break;
+		case 192000:
+			val = SAMPLING_FREQ(0xe) |
+			      ORIGINAL_SAMP_FREQ(1);
+			break;
+		}
+		val |= 4;
+		writel(val, dp->regs + COM_CH_STTS_BITS);
+
+		writel(2, dp->regs + SMPL2PKT_CNTL);
+		writel(2, dp->regs + AUDIO_SRC_CNTL);
+		cdn_dp_reg_write_bit(dp, DP_VB_ID, 4, 1, 0);
+	} else {
+		val = 0x1F0707;
+		writel(val, dp->regs + SPDIF_CTRL_ADDR);
+
+		writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL);
+
+		val = 0x101 | (3 << 11);
+		writel(val, dp->regs + SMPL2PKT_CNFG);
+		writel(2, dp->regs + SMPL2PKT_CNTL);
+
+		val = 0x3F0707;
+		writel(val, dp->regs + SPDIF_CTRL_ADDR);
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
new file mode 100644
index 0000000..74fc7f9
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CDN_DP_REG_H
+#define _CDN_DP_REG_H
+
+#include <linux/bitops.h>
+
+#define ADDR_IMEM		0x10000
+#define ADDR_DMEM		0x20000
+
+/* APB CFG addr */
+#define APB_CTRL			0
+#define XT_INT_CTRL			0x04
+#define MAILBOX_FULL_ADDR		0x08
+#define MAILBOX_EMPTY_ADDR		0x0c
+#define MAILBOX0_WR_DATA		0x10
+#define MAILBOX0_RD_DATA		0x14
+#define KEEP_ALIVE			0x18
+#define VER_L				0x1c
+#define VER_H				0x20
+#define VER_LIB_L_ADDR			0x24
+#define VER_LIB_H_ADDR			0x28
+#define SW_DEBUG_L			0x2c
+#define SW_DEBUG_H			0x30
+#define MAILBOX_INT_MASK		0x34
+#define MAILBOX_INT_STATUS		0x38
+#define SW_CLK_L			0x3c
+#define SW_CLK_H			0x40
+#define SW_EVENTS0			0x44
+#define SW_EVENTS1			0x48
+#define SW_EVENTS2			0x4c
+#define SW_EVENTS3			0x50
+#define XT_OCD_CTRL			0x60
+#define APB_INT_MASK			0x6c
+#define APB_STATUS_MASK			0x70
+
+/* audio decoder addr */
+#define AUDIO_SRC_CNTL			0x30000
+#define AUDIO_SRC_CNFG			0x30004
+#define COM_CH_STTS_BITS		0x30008
+#define STTS_BIT_CH(x)			(0x3000c + (x << 2))
+#define SPDIF_CTRL_ADDR			0x3004c
+#define SPDIF_CH1_CS_3100_ADDR		0x30050
+#define SPDIF_CH1_CS_6332_ADDR		0x30054
+#define SPDIF_CH1_CS_9564_ADDR		0x30058
+#define SPDIF_CH1_CS_12796_ADDR		0x3005c
+#define SPDIF_CH1_CS_159128_ADDR	0x30060
+#define SPDIF_CH1_CS_191160_ADDR	0x30064
+#define SPDIF_CH2_CS_3100_ADDR		0x30068
+#define SPDIF_CH2_CS_6332_ADDR		0x3006c
+#define SPDIF_CH2_CS_9564_ADDR		0x30070
+#define SPDIF_CH2_CS_12796_ADDR		0x30074
+#define SPDIF_CH2_CS_159128_ADDR	0x30078
+#define SPDIF_CH2_CS_191160_ADDR	0x3007c
+#define SMPL2PKT_CNTL			0x30080
+#define SMPL2PKT_CNFG			0x30084
+#define FIFO_CNTL			0x30088
+#define FIFO_STTS			0x3008c
+
+/* source pif addr */
+#define SOURCE_PIF_WR_ADDR		0x30800
+#define SOURCE_PIF_WR_REQ		0x30804
+#define SOURCE_PIF_RD_ADDR		0x30808
+#define SOURCE_PIF_RD_REQ		0x3080c
+#define SOURCE_PIF_DATA_WR		0x30810
+#define SOURCE_PIF_DATA_RD		0x30814
+#define SOURCE_PIF_FIFO1_FLUSH		0x30818
+#define SOURCE_PIF_FIFO2_FLUSH		0x3081c
+#define SOURCE_PIF_STATUS		0x30820
+#define SOURCE_PIF_INTERRUPT_SOURCE	0x30824
+#define SOURCE_PIF_INTERRUPT_MASK	0x30828
+#define SOURCE_PIF_PKT_ALLOC_REG	0x3082c
+#define SOURCE_PIF_PKT_ALLOC_WR_EN	0x30830
+#define SOURCE_PIF_SW_RESET		0x30834
+
+/* bellow registers need access by mailbox */
+/* source car addr */
+#define SOURCE_HDTX_CAR			0x0900
+#define SOURCE_DPTX_CAR			0x0904
+#define SOURCE_PHY_CAR			0x0908
+#define SOURCE_CEC_CAR			0x090c
+#define SOURCE_CBUS_CAR			0x0910
+#define SOURCE_PKT_CAR			0x0918
+#define SOURCE_AIF_CAR			0x091c
+#define SOURCE_CIPHER_CAR		0x0920
+#define SOURCE_CRYPTO_CAR		0x0924
+
+/* clock meters addr */
+#define CM_CTRL				0x0a00
+#define CM_I2S_CTRL			0x0a04
+#define CM_SPDIF_CTRL			0x0a08
+#define CM_VID_CTRL			0x0a0c
+#define CM_LANE_CTRL			0x0a10
+#define I2S_NM_STABLE			0x0a14
+#define I2S_NCTS_STABLE			0x0a18
+#define SPDIF_NM_STABLE			0x0a1c
+#define SPDIF_NCTS_STABLE		0x0a20
+#define NMVID_MEAS_STABLE		0x0a24
+#define I2S_MEAS			0x0a40
+#define SPDIF_MEAS			0x0a80
+#define NMVID_MEAS			0x0ac0
+
+/* source vif addr */
+#define BND_HSYNC2VSYNC			0x0b00
+#define HSYNC2VSYNC_F1_L1		0x0b04
+#define HSYNC2VSYNC_F2_L1		0x0b08
+#define HSYNC2VSYNC_STATUS		0x0b0c
+#define HSYNC2VSYNC_POL_CTRL		0x0b10
+
+/* dptx phy addr */
+#define DP_TX_PHY_CONFIG_REG		0x2000
+#define DP_TX_PHY_STATUS_REG		0x2004
+#define DP_TX_PHY_SW_RESET		0x2008
+#define DP_TX_PHY_SCRAMBLER_SEED	0x200c
+#define DP_TX_PHY_TRAINING_01_04	0x2010
+#define DP_TX_PHY_TRAINING_05_08	0x2014
+#define DP_TX_PHY_TRAINING_09_10	0x2018
+#define TEST_COR			0x23fc
+
+/* dptx hpd addr */
+#define HPD_IRQ_DET_MIN_TIMER		0x2100
+#define HPD_IRQ_DET_MAX_TIMER		0x2104
+#define HPD_UNPLGED_DET_MIN_TIMER	0x2108
+#define HPD_STABLE_TIMER		0x210c
+#define HPD_FILTER_TIMER		0x2110
+#define HPD_EVENT_MASK			0x211c
+#define HPD_EVENT_DET			0x2120
+
+/* dpyx framer addr */
+#define DP_FRAMER_GLOBAL_CONFIG		0x2200
+#define DP_SW_RESET			0x2204
+#define DP_FRAMER_TU			0x2208
+#define DP_FRAMER_PXL_REPR		0x220c
+#define DP_FRAMER_SP			0x2210
+#define AUDIO_PACK_CONTROL		0x2214
+#define DP_VC_TABLE(x)			(0x2218 + (x << 2))
+#define DP_VB_ID			0x2258
+#define DP_MTPH_LVP_CONTROL		0x225c
+#define DP_MTPH_SYMBOL_VALUES		0x2260
+#define DP_MTPH_ECF_CONTROL		0x2264
+#define DP_MTPH_ACT_CONTROL		0x2268
+#define DP_MTPH_STATUS			0x226c
+#define DP_INTERRUPT_SOURCE		0x2270
+#define DP_INTERRUPT_MASK		0x2274
+#define DP_FRONT_BACK_PORCH		0x2278
+#define DP_BYTE_COUNT			0x227c
+
+/* dptx stream addr */
+#define MSA_HORIZONTAL_0		0x2280
+#define MSA_HORIZONTAL_1		0x2284
+#define MSA_VERTICAL_0			0x2288
+#define MSA_VERTICAL_1			0x228c
+#define MSA_MISC			0x2290
+#define STREAM_CONFIG			0x2294
+#define AUDIO_PACK_STATUS		0x2298
+#define VIF_STATUS			0x229c
+#define PCK_STUFF_STATUS_0		0x22a0
+#define PCK_STUFF_STATUS_1		0x22a4
+#define INFO_PACK_STATUS		0x22a8
+#define RATE_GOVERNOR_STATUS		0x22ac
+#define DP_HORIZONTAL			0x22b0
+#define DP_VERTICAL_0			0x22b4
+#define DP_VERTICAL_1			0x22b8
+#define DP_BLOCK_SDP			0x22bc
+
+/* dptx glbl addr */
+#define DPTX_LANE_EN			0x2300
+#define DPTX_ENHNCD			0x2304
+#define DPTX_INT_MASK			0x2308
+#define DPTX_INT_STATUS			0x230c
+
+/* dp aux addr */
+#define DP_AUX_HOST_CONTROL		0x2800
+#define DP_AUX_INTERRUPT_SOURCE		0x2804
+#define DP_AUX_INTERRUPT_MASK		0x2808
+#define DP_AUX_SWAP_INVERSION_CONTROL	0x280c
+#define DP_AUX_SEND_NACK_TRANSACTION	0x2810
+#define DP_AUX_CLEAR_RX			0x2814
+#define DP_AUX_CLEAR_TX			0x2818
+#define DP_AUX_TIMER_STOP		0x281c
+#define DP_AUX_TIMER_CLEAR		0x2820
+#define DP_AUX_RESET_SW			0x2824
+#define DP_AUX_DIVIDE_2M		0x2828
+#define DP_AUX_TX_PREACHARGE_LENGTH	0x282c
+#define DP_AUX_FREQUENCY_1M_MAX		0x2830
+#define DP_AUX_FREQUENCY_1M_MIN		0x2834
+#define DP_AUX_RX_PRE_MIN		0x2838
+#define DP_AUX_RX_PRE_MAX		0x283c
+#define DP_AUX_TIMER_PRESET		0x2840
+#define DP_AUX_NACK_FORMAT		0x2844
+#define DP_AUX_TX_DATA			0x2848
+#define DP_AUX_RX_DATA			0x284c
+#define DP_AUX_TX_STATUS		0x2850
+#define DP_AUX_RX_STATUS		0x2854
+#define DP_AUX_RX_CYCLE_COUNTER		0x2858
+#define DP_AUX_MAIN_STATES		0x285c
+#define DP_AUX_MAIN_TIMER		0x2860
+#define DP_AUX_AFE_OUT			0x2864
+
+/* crypto addr */
+#define CRYPTO_HDCP_REVISION		0x5800
+#define HDCP_CRYPTO_CONFIG		0x5804
+#define CRYPTO_INTERRUPT_SOURCE		0x5808
+#define CRYPTO_INTERRUPT_MASK		0x580c
+#define CRYPTO22_CONFIG			0x5818
+#define CRYPTO22_STATUS			0x581c
+#define SHA_256_DATA_IN			0x583c
+#define SHA_256_DATA_OUT_(x)		(0x5850 + (x << 2))
+#define AES_32_KEY_(x)			(0x5870 + (x << 2))
+#define AES_32_DATA_IN			0x5880
+#define AES_32_DATA_OUT_(x)		(0x5884 + (x << 2))
+#define CRYPTO14_CONFIG			0x58a0
+#define CRYPTO14_STATUS			0x58a4
+#define CRYPTO14_PRNM_OUT		0x58a8
+#define CRYPTO14_KM_0			0x58ac
+#define CRYPTO14_KM_1			0x58b0
+#define CRYPTO14_AN_0			0x58b4
+#define CRYPTO14_AN_1			0x58b8
+#define CRYPTO14_YOUR_KSV_0		0x58bc
+#define CRYPTO14_YOUR_KSV_1		0x58c0
+#define CRYPTO14_MI_0			0x58c4
+#define CRYPTO14_MI_1			0x58c8
+#define CRYPTO14_TI_0			0x58cc
+#define CRYPTO14_KI_0			0x58d0
+#define CRYPTO14_KI_1			0x58d4
+#define CRYPTO14_BLOCKS_NUM		0x58d8
+#define CRYPTO14_KEY_MEM_DATA_0		0x58dc
+#define CRYPTO14_KEY_MEM_DATA_1		0x58e0
+#define CRYPTO14_SHA1_MSG_DATA		0x58e4
+#define CRYPTO14_SHA1_V_VALUE_(x)	(0x58e8 + (x << 2))
+#define TRNG_CTRL			0x58fc
+#define TRNG_DATA_RDY			0x5900
+#define TRNG_DATA			0x5904
+
+/* cipher addr */
+#define HDCP_REVISION			0x60000
+#define INTERRUPT_SOURCE		0x60004
+#define INTERRUPT_MASK			0x60008
+#define HDCP_CIPHER_CONFIG		0x6000c
+#define AES_128_KEY_0			0x60010
+#define AES_128_KEY_1			0x60014
+#define AES_128_KEY_2			0x60018
+#define AES_128_KEY_3			0x6001c
+#define AES_128_RANDOM_0		0x60020
+#define AES_128_RANDOM_1		0x60024
+#define CIPHER14_KM_0			0x60028
+#define CIPHER14_KM_1			0x6002c
+#define CIPHER14_STATUS			0x60030
+#define CIPHER14_RI_PJ_STATUS		0x60034
+#define CIPHER_MODE			0x60038
+#define CIPHER14_AN_0			0x6003c
+#define CIPHER14_AN_1			0x60040
+#define CIPHER22_AUTH			0x60044
+#define CIPHER14_R0_DP_STATUS		0x60048
+#define CIPHER14_BOOTSTRAP		0x6004c
+
+#define APB_IRAM_PATH			BIT(2)
+#define APB_DRAM_PATH			BIT(1)
+#define APB_XT_RESET			BIT(0)
+
+/* mailbox */
+#define MB_OPCODE_ID			0
+#define MB_MODULE_ID			1
+#define MB_SIZE_MSB_ID			2
+#define MB_SIZE_LSB_ID			3
+#define MB_DATA_ID			4
+
+#define MB_MODULE_ID_DP_TX		0x01
+#define MB_MODULE_ID_HDCP_TX		0x07
+#define MB_MODULE_ID_HDCP_RX		0x08
+#define MB_MODULE_ID_HDCP_GENERAL	0x09
+#define MB_MODULE_ID_GENERAL		0x0a
+
+/* general opcode */
+#define GENERAL_MAIN_CONTROL            0x01
+#define GENERAL_TEST_ECHO               0x02
+#define GENERAL_BUS_SETTINGS            0x03
+#define GENERAL_TEST_ACCESS             0x04
+
+#define DPTX_SET_POWER_MNG			0x00
+#define DPTX_SET_HOST_CAPABILITIES		0x01
+#define DPTX_GET_EDID				0x02
+#define DPTX_READ_DPCD				0x03
+#define DPTX_WRITE_DPCD				0x04
+#define DPTX_ENABLE_EVENT			0x05
+#define DPTX_WRITE_REGISTER			0x06
+#define DPTX_READ_REGISTER			0x07
+#define DPTX_WRITE_FIELD			0x08
+#define DPTX_TRAINING_CONTROL			0x09
+#define DPTX_READ_EVENT				0x0a
+#define DPTX_READ_LINK_STAT			0x0b
+#define DPTX_SET_VIDEO				0x0c
+#define DPTX_SET_AUDIO				0x0d
+#define DPTX_GET_LAST_AUX_STAUS			0x0e
+#define DPTX_SET_LINK_BREAK_POINT		0x0f
+#define DPTX_FORCE_LANES			0x10
+#define DPTX_HPD_STATE				0x11
+
+#define DPTX_EVENT_ENABLE_HPD			BIT(0)
+#define DPTX_EVENT_ENABLE_TRAINING		BIT(1)
+
+#define LINK_TRAINING_NOT_ACTIVE		0
+#define LINK_TRAINING_RUN			1
+#define LINK_TRAINING_RESTART			2
+
+#define CONTROL_VIDEO_IDLE			0
+#define CONTROL_VIDEO_VALID			1
+
+#define VIF_BYPASS_INTERLACE			BIT(13)
+#define INTERLACE_FMT_DET			BIT(12)
+#define INTERLACE_DTCT_WIN			0x20
+
+#define DP_FRAMER_SP_INTERLACE_EN		BIT(2)
+#define DP_FRAMER_SP_HSP			BIT(1)
+#define DP_FRAMER_SP_VSP			BIT(0)
+
+/* capability */
+#define AUX_HOST_INVERT				3
+#define	FAST_LT_SUPPORT				1
+#define FAST_LT_NOT_SUPPORT			0
+#define LANE_MAPPING_NORMAL			0xe4
+#define LANE_MAPPING_FLIPPED			0x1b
+#define ENHANCED				1
+
+#define	FULL_LT_STARTED				BIT(0)
+#define FASE_LT_STARTED				BIT(1)
+#define CLK_RECOVERY_FINISHED			BIT(2)
+#define EQ_PHASE_FINISHED			BIT(3)
+#define FASE_LT_START_FINISHED			BIT(4)
+#define CLK_RECOVERY_FAILED			BIT(5)
+#define EQ_PHASE_FAILED				BIT(6)
+#define FASE_LT_FAILED				BIT(7)
+
+#define DPTX_HPD_EVENT				BIT(0)
+#define DPTX_TRAINING_EVENT			BIT(1)
+#define HDCP_TX_STATUS_EVENT			BIT(4)
+#define HDCP2_TX_IS_KM_STORED_EVENT		BIT(5)
+#define HDCP2_TX_STORE_KM_EVENT			BIT(6)
+#define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT	BIT(7)
+
+#define EDID_LENGTH_BYTE			0
+#define EDID_SEGMENT_BUMBER			1
+#define EDID_DATA				2
+#define EDID_BLOCK_SIZE				128
+
+#define TU_SIZE					64
+
+/* audio */
+#define AUDIO_PACK_EN(x)			(x << 8)
+#define SAMPLING_FREQ(x)			(x << 16)
+#define ORIGINAL_SAMP_FREQ(x)			(x << 24)
+#define SYNC_WR_TO_CH_ZERO			BIT(1)
+
+enum voltage_swing_level {
+	VOLTAGE_LEVEL_0,
+	VOLTAGE_LEVEL_1,
+	VOLTAGE_LEVEL_2,
+	VOLTAGE_LEVEL_3,
+};
+
+enum pre_emphasis_level {
+	PRE_EMPHASIS_LEVEL_0,
+	PRE_EMPHASIS_LEVEL_1,
+	PRE_EMPHASIS_LEVEL_2,
+	PRE_EMPHASIS_LEVEL_3,
+};
+
+enum pattern_set {
+	PRBS7		= BIT(0),
+	D10_2		= BIT(1),
+	TRAINING_PTN1	= BIT(2),
+	TRAINING_PTN2	= BIT(3),
+	DP_NONE		= BIT(4)
+};
+
+enum VIC_PXL_ENCODING_FORMAT {
+	PXL_RGB = 0x1,
+	YCBCR_4_4_4 = 0x2,
+	YCBCR_4_2_2 = 0x4,
+	YCBCR_4_2_0 = 0x8,
+	Y_ONLY = 0x10,
+};
+
+enum VIC_COLOR_DEPTH {
+	BCS_6 = 0x1,
+	BCS_8 = 0x2,
+	BCS_10 = 0x4,
+	BCS_12 = 0x8,
+	BCS_16 = 0x10,
+};
+
+#endif /* _CDN_DP_REG_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index edd7ec2..623d9e3 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -969,7 +969,10 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
 		vop_dsp_hold_valid_irq_disable(vop);
 	}
 
-	pin_pol = 0x8;
+	if (s->output_type != DRM_MODE_CONNECTOR_DisplayPort)
+		pin_pol = 0x8;
+	else
+		pin_pol = 0;
 	pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
 	pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
 	VOP_CTRL_SET(vop, pin_pol, pin_pol);
@@ -991,6 +994,10 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
 		VOP_CTRL_SET(vop, mipi_pin_pol, pin_pol);
 		VOP_CTRL_SET(vop, mipi_en, 1);
 		break;
+	case DRM_MODE_CONNECTOR_DisplayPort:
+		VOP_CTRL_SET(vop, dp_pin_pol, pin_pol);
+		VOP_CTRL_SET(vop, dp_en, 1);
+		break;
 	default:
 		DRM_ERROR("unsupport connector_type[%d]\n", s->output_type);
 	}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index ff4f52e..50a045c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -45,6 +45,7 @@ struct vop_ctrl {
 	struct vop_reg edp_en;
 	struct vop_reg hdmi_en;
 	struct vop_reg mipi_en;
+	struct vop_reg dp_en;
 	struct vop_reg out_mode;
 	struct vop_reg dither_down;
 	struct vop_reg dither_up;
@@ -53,6 +54,7 @@ struct vop_ctrl {
 	struct vop_reg hdmi_pin_pol;
 	struct vop_reg edp_pin_pol;
 	struct vop_reg mipi_pin_pol;
+	struct vop_reg dp_pin_pol;
 
 	struct vop_reg htotal_pw;
 	struct vop_reg hact_st_end;
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 5b1ae1f..dcf172e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -281,6 +281,7 @@ static const struct vop_data rk3288_vop = {
 static const struct vop_ctrl rk3399_ctrl_data = {
 	.standby = VOP_REG(RK3399_SYS_CTRL, 0x1, 22),
 	.gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23),
+	.dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11),
 	.rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12),
 	.hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13),
 	.edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14),
@@ -290,6 +291,7 @@ static const struct vop_ctrl rk3399_ctrl_data = {
 	.data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19),
 	.out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0),
 	.rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16),
+	.dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16),
 	.hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 20),
 	.edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 24),
 	.mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 28),
diff --git a/include/sound/cdn-dp-audio.h b/include/sound/cdn-dp-audio.h
new file mode 100644
index 0000000..8c6e55c
--- /dev/null
+++ b/include/sound/cdn-dp-audio.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CDN_DP_AUDIO_H__
+#define __CDN_DP_AUDIO_H__
+
+#include <linux/platform_device.h>
+
+#define AUDIO_TYPE_I2S			0
+#define AUDIO_TYPE_SPIDIF_INTERNAL	1
+#define AUDIO_TYPE_SPIDIF_EXTERNAL	2
+
+enum AUDIO_TYPE {
+	TYPE_I2S = 0,
+	TYPE_SPDIF = 1,
+};
+
+struct audio_info {
+	enum AUDIO_TYPE type;
+	int freq;
+	int channels;
+	int word_length;
+};
+
+struct cdn_dp_audio_ops {
+	int (*audio_startup)(void *dp_dev, struct audio_info *audio);
+	int (*audio_shutdown)(void *dp_dev, struct audio_info *audio);
+	int (*audio_start)(void *dp_dev, struct audio_info *audio);
+	int (*audio_stop)(void *dp_dev, struct audio_info *audio);
+	int (*audio_config)(void *dp_dev, struct audio_info *audio);
+};
+
+/* DP audio initalization data */
+struct cdn_dp_audio_pdata {
+	struct device *dev;
+	const struct cdn_dp_audio_ops *ops;
+	void *data;
+};
+
+#endif /* __CDN_DP_AUDIO_H__ */
-- 
2.6.3



From zyw at rock-chips.com  Thu May 26 23:02:17 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 14:02:17 +0800
Subject: [PATCH 4/6] Documentation: bindings: add dt documentation for cdn DP
 controller
In-Reply-To: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464328939-8073-5-git-send-email-zyw@rock-chips.com>

This patch adds a binding that describes the cdn DP controller for
rk3399.

Signed-off-by: Chris Zhong <zyw at rock-chips.com>
---

 .../bindings/display/rockchip/cdn-dp-rockchip.txt  | 57 ++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt

diff --git a/Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt
new file mode 100644
index 0000000..60795c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt
@@ -0,0 +1,57 @@
+Rockchip RK3399 specific extensions to the cdn Display Port
+================================
+
+Required properties:
+- compatible: "rockchip,cdn-dp"
+
+- reg: physical base address of the controller and length
+
+- clocks: from common clock binding: handle to dp clock.
+
+- clock-names: from common clock binding:
+	       Required elements: "core_clk" "pclk" "spdif"
+
+- rockchip,grf: this soc should set GRF regs, so need get grf here.
+
+- ports: contain a port nodes with endpoint definitions as defined in
+	 Documentation/devicetree/bindings/media/video-interfaces.txt.
+	 contained 2 endpoints, connecting to the output of vop.
+
+- phys: from general PHY binding: the phandle for the PHY device.
+
+-------------------------------------------------------------------------------
+
+Example:
+	cdn_dp: dp at fec00000 {
+		compatible = "rockchip,cdn-dp";
+		reg = <0x0 0xfec00000 0x0 0x100000>;
+		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru SCLK_DP_CORE>, <&cru PCLK_DP_CTRL>,
+			 <&cru SCLK_SPDIF_REC_DPTX>;
+		clock-names = "core_clk", "pclk", "spdif";
+		phys = <&tcphy0>;
+		rockchip,grf = <&grf>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			dp_in: port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				dp_in_vopb: endpoint at 0 {
+					reg = <0>;
+					remote-endpoint = <&vopb_out_dp>;
+				};
+
+				dp_in_vopl: endpoint at 1 {
+					reg = <1>;
+					remote-endpoint = <&vopl_out_dp>;
+				};
+			};
+		};
+	};
-- 
2.6.3



From zyw at rock-chips.com  Thu May 26 23:02:18 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 14:02:18 +0800
Subject: [PATCH 5/6] ASoC: cdn-dp: Add cdn DP codec driver
In-Reply-To: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464328939-8073-6-git-send-email-zyw@rock-chips.com>

codec driver get some interfaces from cdn-dp driver, than using those
to set DP audio formats, corresponding to alsa formats.

Signed-off-by: Chris Zhong <zyw at rock-chips.com>
---

 sound/soc/codecs/Kconfig        |   3 +
 sound/soc/codecs/Makefile       |   2 +
 sound/soc/codecs/cdn-dp-audio.c | 246 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 251 insertions(+)
 create mode 100644 sound/soc/codecs/cdn-dp-audio.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 7ef3a0c..7ddae65 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -365,6 +365,9 @@ config SND_SOC_ALC5623
 config SND_SOC_ALC5632
 	tristate
 
+config SND_SOC_CDN_DP_AUDIO
+	tristate
+
 config SND_SOC_CQ0093VC
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 185a712..7a703a7 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -32,6 +32,7 @@ snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-ak5386-objs := ak5386.o
 snd-soc-arizona-objs := arizona.o
+snd-soc-cdn-dp-audio-objs := cdn-dp-audio.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cs35l32-objs := cs35l32.o
 snd-soc-cs42l51-objs := cs42l51.o
@@ -241,6 +242,7 @@ obj-$(CONFIG_SND_SOC_AK5386)	+= snd-soc-ak5386.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5632)	+= snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_ARIZONA)	+= snd-soc-arizona.o
+obj-$(CONFIG_SND_SOC_CDN_DP_AUDIO) += snd-soc-cdn-dp-audio.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
 obj-$(CONFIG_SND_SOC_CS35L32)	+= snd-soc-cs35l32.o
 obj-$(CONFIG_SND_SOC_CS42L51)	+= snd-soc-cs42l51.o
diff --git a/sound/soc/codecs/cdn-dp-audio.c b/sound/soc/codecs/cdn-dp-audio.c
new file mode 100644
index 0000000..a68570f
--- /dev/null
+++ b/sound/soc/codecs/cdn-dp-audio.c
@@ -0,0 +1,246 @@
+/*
+ * cdn dp audio support library
+ *
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+
+#include <sound/cdn-dp-audio.h>
+
+#define DRV_NAME "cdn-dp-audio"
+
+struct snd_cdn_dp_audio {
+	struct device *dev;
+	const struct cdn_dp_audio_ops *ops;
+	void *data;
+	bool is_playback_status;
+};
+
+static int snd_cdn_dp_audio_dai_startup(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *codec_dai)
+{
+	struct snd_cdn_dp_audio *ad = snd_soc_dai_get_drvdata(codec_dai);
+	struct audio_info audio;
+
+	ad->is_playback_status = true;
+	ad->ops->audio_startup(ad->data, &audio);
+
+	return 0;
+}
+
+static int snd_cdn_dp_audio_dai_hw_params(struct snd_pcm_substream *substream,
+					  struct snd_pcm_hw_params *params,
+					  struct snd_soc_dai *codec_dai)
+{
+	struct snd_cdn_dp_audio *ad = snd_soc_dai_get_drvdata(codec_dai);
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct audio_info audio;
+	unsigned int fmt, rate, chan, width;
+
+	fmt = rtd->dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+	if (fmt == SND_SOC_DAIFMT_I2S) {
+		audio.type = AUDIO_TYPE_I2S;
+	} else {
+		dev_err(codec_dai->dev, "DAI format unsupported");
+		return -EINVAL;
+	}
+
+	width = params_width(params);
+	if ((width == 16) || (width == 24)) {
+		audio.word_length = width;
+	} else {
+		dev_err(codec_dai->dev, "width[%d] not support!\n", width);
+		return -EINVAL;
+	}
+
+	chan = params_channels(params);
+	switch (chan) {
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+		audio.channels = chan;
+		break;
+	default:
+		dev_err(codec_dai->dev, "channel[%d] not support!\n", chan);
+		return -EINVAL;
+	}
+
+	rate = params_rate(params);
+	switch (rate) {
+	case 32000:
+	case 44100:
+	case 48000:
+	case 88200:
+	case 96000:
+	case 176400:
+	case 192000:
+		audio.freq = rate;
+		break;
+	default:
+		dev_err(codec_dai->dev, "rate[%d] not support!\n", rate);
+		return -EINVAL;
+	}
+
+	ad->ops->audio_config(ad->data, &audio);
+
+	return 0;
+}
+
+static int snd_cdn_dp_audio_dai_trigger(struct snd_pcm_substream *substream,
+					int cmd, struct snd_soc_dai *codec_dai)
+{
+	struct snd_cdn_dp_audio *ad = snd_soc_dai_get_drvdata(codec_dai);
+	struct audio_info audio;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ad->ops->audio_start(ad->data, &audio);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ad->ops->audio_stop(ad->data, &audio);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void snd_cdn_dp_audio_dai_shutdown(struct snd_pcm_substream *substream,
+					  struct snd_soc_dai *codec_dai)
+{
+	struct snd_cdn_dp_audio *ad = snd_soc_dai_get_drvdata(codec_dai);
+	struct audio_info audio;
+
+	ad->is_playback_status = false;
+	ad->ops->audio_shutdown(ad->data, &audio);
+}
+
+static const struct snd_soc_dapm_widget snd_cdn_dp_audio_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route snd_cdn_dp_audio_routes[] = {
+	{ "TX", NULL, "Playback" },
+};
+
+static const struct snd_soc_dai_ops cdn_dp_audio_dai_ops = {
+	.startup = snd_cdn_dp_audio_dai_startup,
+	.hw_params = snd_cdn_dp_audio_dai_hw_params,
+	.trigger = snd_cdn_dp_audio_dai_trigger,
+	.shutdown = snd_cdn_dp_audio_dai_shutdown,
+};
+
+static struct snd_soc_dai_driver cdn_dp_audio_dai = {
+	.name = "cdn-dp-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_32000 |
+			 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+			 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_32000 |
+			 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+			 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+
+	.ops = &cdn_dp_audio_dai_ops,
+};
+
+static const struct snd_soc_codec_driver cdn_dp_audio = {
+	.dapm_widgets = snd_cdn_dp_audio_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(snd_cdn_dp_audio_widgets),
+	.dapm_routes = snd_cdn_dp_audio_routes,
+	.num_dapm_routes = ARRAY_SIZE(snd_cdn_dp_audio_routes),
+};
+
+static int cdn_dp_audio_probe(struct platform_device *pdev)
+{
+	struct cdn_dp_audio_pdata *pdata = pdev->dev.platform_data;
+	struct snd_cdn_dp_audio *ad;
+	int ret;
+
+	ad = devm_kzalloc(&pdev->dev, sizeof(*ad), GFP_KERNEL);
+	if (!ad)
+		return -ENOMEM;
+
+	ad->dev = pdata->dev;
+	ad->ops = pdata->ops;
+	ad->data = pdata->data;
+
+	platform_set_drvdata(pdev, ad);
+
+	ret = snd_soc_register_codec(&pdev->dev, &cdn_dp_audio,
+				     &cdn_dp_audio_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "register codec failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int cdn_dp_audio_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id cdn_dp_audio_ids[] = {
+	{ .compatible = "cdn-dp-audio", },
+	{ }
+};
+
+static struct platform_driver cdn_dp_audio_driver = {
+	.driver = {
+		.name = "cdn-dp-audio",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(cdn_dp_audio_ids),
+	},
+	.probe = cdn_dp_audio_probe,
+	.remove = cdn_dp_audio_remove,
+};
+module_platform_driver(cdn_dp_audio_driver);
+
+MODULE_AUTHOR("Chris Zhong <zyw at rock-chips.com>");
+MODULE_DESCRIPTION("CDN DP Audio ASoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform: cdn-dp-audio");
+MODULE_DEVICE_TABLE(of, cdn_dp_audio_ids);
-- 
2.6.3



From zyw at rock-chips.com  Thu May 26 23:02:19 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 14:02:19 +0800
Subject: [PATCH 6/6] ASoC: rockchip: Add machine driver for cdn dp codec
In-Reply-To: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464328939-8073-7-git-send-email-zyw@rock-chips.com>

The driver is used for cdn dp codec embedded in rk3399

Signed-off-by: Chris Zhong <zyw at rock-chips.com>

---

 .../bindings/sound/rockchip-cdn-dp-audio.txt       |  12 ++
 sound/soc/rockchip/Kconfig                         |   9 ++
 sound/soc/rockchip/Makefile                        |   2 +
 sound/soc/rockchip/rockchip-cdn-dp-audio.c         | 167 +++++++++++++++++++++
 4 files changed, 190 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip-cdn-dp-audio.txt
 create mode 100644 sound/soc/rockchip/rockchip-cdn-dp-audio.c

diff --git a/Documentation/devicetree/bindings/sound/rockchip-cdn-dp-audio.txt b/Documentation/devicetree/bindings/sound/rockchip-cdn-dp-audio.txt
new file mode 100644
index 0000000..b7b0898
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip-cdn-dp-audio.txt
@@ -0,0 +1,12 @@
+Rockchip cdn dp audio bindings
+
+Required properties:
+- compatible: platform specific, must be "rockchip,cdn-dp-audio"
+- i2s-controller: the device of i2s controller
+
+Example:
+
+	cdn_dp_audio: cdn-dp_audio {
+		compatible = "rockchip,cdn-dp-audio";
+		i2s-controller = <&i2s2>;
+	};
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index f1e0c70..7e7d905 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -15,6 +15,15 @@ config SND_SOC_ROCKCHIP_I2S
 	  Rockchip I2S device. The device supports upto maximum of
 	  8 channels each for play and record.
 
+config SND_SOC_ROCKCHIP_CDN_DP_AUDIO
+	tristate "cdn DP audio support"
+	depends on ROCKCHIP_CDN_DP
+	select SND_SOC_ROCKCHIP_I2S
+	select SND_SOC_CDN_DP_AUDIO
+	help
+	  Say Y or M here if you want to add support for SoC audio on Rockchip
+	  boards using the cdn dp codec, such as RK3399.
+
 config SND_SOC_ROCKCHIP_SPDIF
 	tristate "Rockchip SPDIF Device Driver"
 	depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index c0bf560..9367f55 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -5,8 +5,10 @@ snd-soc-rockchip-spdif-objs := rockchip_spdif.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
 
+snd-soc-rockchip-cdn-dp-objs := rockchip-cdn-dp-audio.o
 snd-soc-rockchip-max98090-objs := rockchip_max98090.o
 snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
 
+obj-$(CONFIG_SND_SOC_ROCKCHIP_CDN_DP_AUDIO) += snd-soc-rockchip-cdn-dp.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
diff --git a/sound/soc/rockchip/rockchip-cdn-dp-audio.c b/sound/soc/rockchip/rockchip-cdn-dp-audio.c
new file mode 100644
index 0000000..2bf6649
--- /dev/null
+++ b/sound/soc/rockchip/rockchip-cdn-dp-audio.c
@@ -0,0 +1,167 @@
+/*
+ * rockchip-cdn-dp-card.c
+ *
+ * ROCKCHIP ALSA SoC DAI driver for cdn dp audio on rockchip processors.
+ *
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+
+#include "rockchip_i2s.h"
+
+#define DRV_NAME "rockchip-cdn-dp-audio"
+
+static int cdn_dp_audio_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int dai_fmt = rtd->dai_link->dai_fmt;
+	int mclk, ret;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 24000:
+	case 32000:
+	case 48000:
+	case 64000:
+	case 96000:
+		mclk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+	case 88200:
+		mclk = 11289600;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
+	if (ret < 0) {
+		dev_err(cpu_dai->dev, "failed to set cpu_dai fmt.\n");
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(cpu_dai->dev, "failed to set cpu_dai sysclk.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops cdn_dp_dai_ops = {
+	.hw_params = cdn_dp_audio_hw_params,
+};
+
+static struct snd_soc_dai_link cdn_dp_dai = {
+	.name = "cdn_dp",
+	.stream_name = "cdn_dp",
+	.codec_name = "cdn-dp-audio",
+	.codec_dai_name = "cdn-dp-hifi",
+	.ops = &cdn_dp_dai_ops,
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		   SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card cdn_dp_audio_card = {
+	.name = "cdn_dp",
+	.owner = THIS_MODULE,
+	.dai_link = &cdn_dp_dai,
+	.num_links = 1,
+};
+
+static int cdn_dp_audio_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &cdn_dp_audio_card;
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+
+	cdn_dp_dai.cpu_of_node = of_parse_phandle(np, "i2s-controller", 0);
+	if (!cdn_dp_dai.cpu_of_node) {
+		dev_err(&pdev->dev, "Property 'i2s-controller' missing !\n");
+		goto free_priv_data;
+	}
+
+	cdn_dp_dai.platform_of_node = cdn_dp_dai.cpu_of_node;
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "register card failed (%d)\n", ret);
+		card->dev = NULL;
+		goto free_cpu_of_node;
+	}
+
+	dev_info(&pdev->dev, "rockchip cdn dp audio init success.\n");
+
+	return 0;
+
+free_cpu_of_node:
+	cdn_dp_dai.cpu_of_node = NULL;
+	cdn_dp_dai.platform_of_node = NULL;
+free_priv_data:
+	snd_soc_card_set_drvdata(card, NULL);
+	platform_set_drvdata(pdev, NULL);
+	card->dev = NULL;
+
+	return ret;
+}
+
+static int cdn_dp_audio_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
+	snd_soc_card_set_drvdata(card, NULL);
+	platform_set_drvdata(pdev, NULL);
+	card->dev = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id cdn_dp_audio_of_match[] = {
+	{ .compatible = "rockchip,cdn-dp-audio", },
+	{},
+};
+
+static struct platform_driver cdn_dp_audio_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = cdn_dp_audio_of_match,
+	},
+	.probe = cdn_dp_audio_probe,
+	.remove = cdn_dp_audio_remove,
+};
+module_platform_driver(cdn_dp_audio_driver);
+
+MODULE_AUTHOR("Chris Zhong <zyw at rock-chips.com>");
+MODULE_DESCRIPTION("CDN DP Audio ASoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, cdn_dp_audio_of_match);
-- 
2.6.3



From ykk at rock-chips.com  Thu May 26 23:16:40 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Fri, 27 May 2016 14:16:40 +0800
Subject: [PATCH v2 0/10] Add RK3399 eDP support and fix some bugs to
 analogix_dp driver.
In-Reply-To: <4e1c65f8-5a5b-dbb9-35fe-ef09c0758536@osg.samsung.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
 <5746C321.9000707@rock-chips.com>
 <4e1c65f8-5a5b-dbb9-35fe-ef09c0758536@osg.samsung.com>
Message-ID: <5747E648.6020100@rock-chips.com>

Hi Javier,

On 05/26/2016 08:48 PM, Javier Martinez Canillas wrote:
> Hello Yakir,
>
> On 05/26/2016 05:34 AM, Yakir Yang wrote:
>> Hi Javier,
>>
>> On 05/24/2016 01:01 PM, Yakir Yang wrote:
>>> Hi all,
>>>
>>> This series have been posted about one month, still no comments, help here :(
>> This series works rightly on Rockchip platform, and most of them haven't touch the
>> common analogix_dp driver (except for the hotplug fixed). So i guess Exynos platform
>> should also happy with this changes.
>>
>> But not sure about that. So, is it possible that you could help to check this on Exynos
>> Chromebook, if so i would be very grateful about that.
>>
> Of course, I' ll test. Could you please provide me a branch that I can
> pull directly to avoid cherry-picking all the patches from the list?
>   
Ah, thanks a lot, I do have a tree 
https://github.com/yakir-Yang/linux/tree/fromlist/3399-edp

- Yakir
>> Thanks,
>> - Yakir
> Best regards,




From shawn.lin at rock-chips.com  Thu May 26 23:36:40 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 27 May 2016 14:36:40 +0800
Subject: [PATCH v2 1/2] mmc: dw_mmc: remove redundant of set_bit and clear_bit
Message-ID: <1464331000-16230-1-git-send-email-shawn.lin@rock-chips.com>

dw_mci_get_cd have already dealt with these for
both of internal card-detect and gpio card-detect.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

---

Changes in v2: None

 drivers/mmc/host/dw_mmc.c | 5 +----
 1 file changed, 1 insertion(+), 4 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 829a6ee..cb30e91 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -2616,10 +2616,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
 		mmc->max_seg_size = mmc->max_req_size;
 	}
 
-	if (dw_mci_get_cd(mmc))
-		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
-	else
-		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
+	dw_mci_get_cd(mmc);
 
 	ret = mmc_add_host(mmc);
 	if (ret)
-- 
2.3.7




From shawn.lin at rock-chips.com  Thu May 26 23:37:05 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 27 May 2016 14:37:05 +0800
Subject: [PATCH v2 2/2] mmc: dw_mmc: check card present before starting request
Message-ID: <1464331025-16275-1-git-send-email-shawn.lin@rock-chips.com>

The main reason to add this check is to avoid unnecessary
mmc_request like the on-going cmd and the corresponding sbc
if the card is removed. Although we have already checked this in
dw_mci_handle_cd for runtime usage of sd card and dw_mci_init_slot
for noremovable devices, but there is a timing gap before it really
calls dw_mci_get_cd as mmc_detect_change needs some delay here.

Another gain here is that we could save some checkings of card status
after sd card been removed.

Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

---

Changes in v2:
- hold lock before dw_mci_queue_request

 drivers/mmc/host/dw_mmc.c | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index cb30e91..2b4b3df 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -105,6 +105,7 @@ struct idmac_desc {
 static bool dw_mci_reset(struct dw_mci *host);
 static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
 static int dw_mci_card_busy(struct mmc_host *mmc);
+static int dw_mci_get_cd(struct mmc_host *mmc);
 
 #if defined(CONFIG_DEBUG_FS)
 static int dw_mci_req_show(struct seq_file *s, void *v)
@@ -1253,15 +1254,15 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
 	 * atomic, otherwise the card could be removed in between and the
 	 * request wouldn't fail until another card was inserted.
 	 */
-	spin_lock_bh(&host->lock);
 
-	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
-		spin_unlock_bh(&host->lock);
+	if (!dw_mci_get_cd(mmc)) {
 		mrq->cmd->error = -ENOMEDIUM;
 		mmc_request_done(mmc, mrq);
 		return;
 	}
 
+	spin_lock_bh(&host->lock);
+
 	dw_mci_queue_request(host, slot, mrq);
 
 	spin_unlock_bh(&host->lock);
-- 
2.3.7




From shawn.lin at rock-chips.com  Thu May 26 23:45:48 2016
From: shawn.lin at rock-chips.com (Shawn Lin)
Date: Fri, 27 May 2016 14:45:48 +0800
Subject: [PATCH v6 3/5] mmc: core: implement enhanced strobe support
In-Reply-To: <5746D854.1020200@intel.com>
References: <1464227707-30616-1-git-send-email-shawn.lin@rock-chips.com>
 <1464227782-31296-1-git-send-email-shawn.lin@rock-chips.com>
 <5746D854.1020200@intel.com>
Message-ID: <944f9a21-8296-c29d-cccf-f9588aceab4a@rock-chips.com>

? 2016/5/26 19:04, Adrian Hunter ??:
> On 26/05/16 04:56, Shawn Lin wrote:
>> Controllers use data strobe line to latch data from devices
>> under hs400 mode, but not for cmd line. So since emmc 5.1, JEDEC
>> introduces enhanced strobe mode for latching cmd response from
>> emmc devices to host controllers. This new feature is optional,
>> so it depends both on device's cap and host's cap to decide
>> whether to use it or not.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>
> I have a couple of comments below, but they don't necessarily require any
> action, so:
>
> Acked-by: Adrian Hunter <adrian.hunter at intel.com>
>
>>
>> Reviewed-by: Jaehoon Chung <jh80.chung at samsung.com>
>> Tested-by: Douglas Anderson <dianders at chromium.org>
>> Tested-by: Jaehoon Chung <jh80.chung at samsung.com>
>> ---
>>
>> Changes in v6:
>> - add Doug's test-tag and Jaehoon's review-test-tag
>>
>> Changes in v5: None
>> Changes in v4: None
>> Changes in v3: None
>> Changes in v2: None
>>
>>  drivers/mmc/core/bus.c   |  3 +-
>>  drivers/mmc/core/core.c  |  9 ++++++
>>  drivers/mmc/core/mmc.c   | 84 ++++++++++++++++++++++++++++++++++++++++++++++--
>>  include/linux/mmc/card.h |  1 +
>>  include/linux/mmc/host.h | 11 +++++++
>>  include/linux/mmc/mmc.h  |  3 ++
>>  6 files changed, 108 insertions(+), 3 deletions(-)
>>
>> diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
>> index 4bc48f1..c64266f 100644
>> --- a/drivers/mmc/core/bus.c
>> +++ b/drivers/mmc/core/bus.c
>> @@ -332,12 +332,13 @@ int mmc_add_card(struct mmc_card *card)
>>  			mmc_card_ddr52(card) ? "DDR " : "",
>>  			type);
>>  	} else {
>> -		pr_info("%s: new %s%s%s%s%s card at address %04x\n",
>> +		pr_info("%s: new %s%s%s%s%s%s card at address %04x\n",
>>  			mmc_hostname(card->host),
>>  			mmc_card_uhs(card) ? "ultra high speed " :
>>  			(mmc_card_hs(card) ? "high speed " : ""),
>>  			mmc_card_hs400(card) ? "HS400 " :
>>  			(mmc_card_hs200(card) ? "HS200 " : ""),
>> +			mmc_card_hs400es(card) ? "Enhanced strobe " : "",
>>  			mmc_card_ddr52(card) ? "DDR " : "",
>>  			uhs_bus_speed_mode, type, card->rca);
>>  	}
>> diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
>> index 99275e4..b0c1f07 100644
>> --- a/drivers/mmc/core/core.c
>> +++ b/drivers/mmc/core/core.c
>> @@ -1127,6 +1127,15 @@ void mmc_set_initial_state(struct mmc_host *host)
>>  	host->ios.bus_width = MMC_BUS_WIDTH_1;
>>  	host->ios.timing = MMC_TIMING_LEGACY;
>>  	host->ios.drv_type = 0;
>> +	host->ios.enhanced_strobe = false;
>> +
>> +	/*
>> +	 * Make sure we are in non-enhanced strobe mode before we
>> +	 * actually enable it in ext_csd.
>> +	 */
>> +	if ((host->caps2 & MMC_CAP2_HS400_ES) &&
>> +	     host->ops->hs400_enhanced_strobe)
>> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
>>
>>  	mmc_set_ios(host);
>>  }
>> diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
>> index f99c47e..9dc91ba 100644
>> --- a/drivers/mmc/core/mmc.c
>> +++ b/drivers/mmc/core/mmc.c
>> @@ -235,6 +235,11 @@ static void mmc_select_card_type(struct mmc_card *card)
>>  		avail_type |= EXT_CSD_CARD_TYPE_HS400_1_2V;
>>  	}
>>
>> +	if ((caps2 & MMC_CAP2_HS400_ES) &&
>> +	    card->ext_csd.strobe_support &&
>> +	    (avail_type & EXT_CSD_CARD_TYPE_HS400))
>> +		avail_type |= EXT_CSD_CARD_TYPE_HS400ES;
>> +
>>  	card->ext_csd.hs_max_dtr = hs_max_dtr;
>>  	card->ext_csd.hs200_max_dtr = hs200_max_dtr;
>>  	card->mmc_avail_type = avail_type;
>> @@ -383,6 +388,7 @@ static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
>>  			mmc_card_set_blockaddr(card);
>>  	}
>>
>> +	card->ext_csd.strobe_support = ext_csd[EXT_CSD_STROBE_SUPPORT];
>>  	card->ext_csd.raw_card_type = ext_csd[EXT_CSD_CARD_TYPE];
>>  	mmc_select_card_type(card);
>>
>> @@ -1216,6 +1222,78 @@ out_err:
>>  	return err;
>>  }
>>
>> +static int mmc_select_hs400es(struct mmc_card *card)
>> +{
>> +	struct mmc_host *host = card->host;
>> +	int err = 0;
>> +	u8 val;
>> +
>> +	if (!(host->caps & MMC_CAP_8_BIT_DATA)) {
>> +		err = -ENOTSUPP;
>> +		goto out_err;
>> +	}
>> +
>> +	err = mmc_select_bus_width(card);
>> +	if (IS_ERR_VALUE(err))
>> +		goto out_err;
>> +
>> +	/* Switch card to HS mode */
>> +	err = mmc_select_hs(card);
>> +	if (err) {
>> +		pr_err("%s: switch to high-speed failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	err = mmc_switch_status(card);
>> +	if (err)
>> +		goto out_err;
>
> The spec. says "switch to High Speed mode and then set the clock frequency
> to a value not greater than 52 MHz" which would tend to imply changing to
> the High Speed frequency here. It shouldn't make any difference, so I don't
> know if it is worth doing.

yes, it should't make any difference as we are already assign a clock
freq not greater than 52M(400k should also work for Highspeed).

>
>> +
>> +	/* Switch card to DDR with strobe bit */
>> +	val = EXT_CSD_DDR_BUS_WIDTH_8 | EXT_CSD_BUS_WIDTH_STROBE;
>> +	err = mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +			 EXT_CSD_BUS_WIDTH,
>> +			 val,
>> +			 card->ext_csd.generic_cmd6_time);
>> +	if (err) {
>> +		pr_err("%s: switch to bus width for hs400es failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	/* Switch card to HS400 */
>> +	val = EXT_CSD_TIMING_HS400 |
>> +	      card->drive_strength << EXT_CSD_DRV_STR_SHIFT;
>> +	err = __mmc_switch(card, EXT_CSD_CMD_SET_NORMAL,
>> +			   EXT_CSD_HS_TIMING, val,
>> +			   card->ext_csd.generic_cmd6_time,
>> +			   true, false, true);
>> +	if (err) {
>> +		pr_err("%s: switch to hs400es failed, err:%d\n",
>> +			mmc_hostname(host), err);
>> +		goto out_err;
>> +	}
>> +
>> +	/* Set host controller to HS400 timing and frequency */
>> +	mmc_set_timing(host, MMC_TIMING_MMC_HS400);
>> +
>> +	/* Controller enable enhanced strobe function */
>> +	host->ios.enhanced_strobe = true;
>> +	if (host->ops->hs400_enhanced_strobe)
>> +		host->ops->hs400_enhanced_strobe(host, &host->ios);
>> +
>
> And again here, if we followed the spec. exactly we would change to the
> HS400 frequency here rather than after sending CMD13. Again, it shouldn't
> make any difference, so I don't if it is worth doing.

I delayed the response to your comment as I have been tring some
different eMMC devices to see whether it makes any difference. Now I
it's OK. :)

Thanks.

>
>> +	err = mmc_switch_status(card);
>> +	if (err)
>> +		goto out_err;
>> +
>> +	return 0;
>> +
>> +out_err:
>> +	pr_err("%s: %s failed, error %d\n", mmc_hostname(card->host),
>> +	       __func__, err);
>> +	return err;
>> +}
>> +
>>  static void mmc_select_driver_type(struct mmc_card *card)
>>  {
>>  	int card_drv_type, drive_strength, drv_type;
>> @@ -1297,7 +1375,7 @@ err:
>>  }
>>
>>  /*
>> - * Activate High Speed or HS200 mode if supported.
>> + * Activate High Speed, HS200 or HS400ES mode if supported.
>>   */
>>  static int mmc_select_timing(struct mmc_card *card)
>>  {
>> @@ -1306,7 +1384,9 @@ static int mmc_select_timing(struct mmc_card *card)
>>  	if (!mmc_can_ext_csd(card))
>>  		goto bus_speed;
>>
>> -	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>> +	if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS400ES)
>> +		err = mmc_select_hs400es(card);
>> +	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
>>  		err = mmc_select_hs200(card);
>>  	else if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS)
>>  		err = mmc_select_hs(card);
>> diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
>> index eb0151b..22defc2 100644
>> --- a/include/linux/mmc/card.h
>> +++ b/include/linux/mmc/card.h
>> @@ -95,6 +95,7 @@ struct mmc_ext_csd {
>>  	u8			raw_partition_support;	/* 160 */
>>  	u8			raw_rpmb_size_mult;	/* 168 */
>>  	u8			raw_erased_mem_count;	/* 181 */
>> +	u8			strobe_support;		/* 184 */
>>  	u8			raw_ext_csd_structure;	/* 194 */
>>  	u8			raw_card_type;		/* 196 */
>>  	u8			raw_driver_strength;	/* 197 */
>> diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
>> index 2a06fb0..0eabb72 100644
>> --- a/include/linux/mmc/host.h
>> +++ b/include/linux/mmc/host.h
>> @@ -19,6 +19,7 @@
>>
>>  #include <linux/mmc/core.h>
>>  #include <linux/mmc/card.h>
>> +#include <linux/mmc/mmc.h>
>>  #include <linux/mmc/pm.h>
>>
>>  struct mmc_ios {
>> @@ -77,6 +78,8 @@ struct mmc_ios {
>>  #define MMC_SET_DRIVER_TYPE_A	1
>>  #define MMC_SET_DRIVER_TYPE_C	2
>>  #define MMC_SET_DRIVER_TYPE_D	3
>> +
>> +	bool enhanced_strobe;			/* hs400es selection */
>>  };
>>
>>  struct mmc_host_ops {
>> @@ -143,6 +146,9 @@ struct mmc_host_ops {
>>
>>  	/* Prepare HS400 target operating frequency depending host driver */
>>  	int	(*prepare_hs400_tuning)(struct mmc_host *host, struct mmc_ios *ios);
>> +	/* Prepare enhanced strobe depending host driver */
>> +	void	(*hs400_enhanced_strobe)(struct mmc_host *host,
>> +					 struct mmc_ios *ios);
>>  	int	(*select_drive_strength)(struct mmc_card *card,
>>  					 unsigned int max_dtr, int host_drv,
>>  					 int card_drv, int *drv_type);
>> @@ -513,6 +519,11 @@ static inline bool mmc_card_hs400(struct mmc_card *card)
>>  	return card->host->ios.timing == MMC_TIMING_MMC_HS400;
>>  }
>>
>> +static inline bool mmc_card_hs400es(struct mmc_card *card)
>> +{
>> +	return card->host->ios.enhanced_strobe;
>> +}
>> +
>>  void mmc_retune_timer_stop(struct mmc_host *host);
>>
>>  static inline void mmc_retune_needed(struct mmc_host *host)
>> diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
>> index 15f2c4a..c376209 100644
>> --- a/include/linux/mmc/mmc.h
>> +++ b/include/linux/mmc/mmc.h
>> @@ -297,6 +297,7 @@ struct _mmc_csd {
>>  #define EXT_CSD_PART_CONFIG		179	/* R/W */
>>  #define EXT_CSD_ERASED_MEM_CONT		181	/* RO */
>>  #define EXT_CSD_BUS_WIDTH		183	/* R/W */
>> +#define EXT_CSD_STROBE_SUPPORT		184	/* RO */
>>  #define EXT_CSD_HS_TIMING		185	/* R/W */
>>  #define EXT_CSD_POWER_CLASS		187	/* R/W */
>>  #define EXT_CSD_REV			192	/* RO */
>> @@ -380,12 +381,14 @@ struct _mmc_csd {
>>  #define EXT_CSD_CARD_TYPE_HS400_1_2V	(1<<7)	/* Card can run at 200MHz DDR, 1.2V */
>>  #define EXT_CSD_CARD_TYPE_HS400		(EXT_CSD_CARD_TYPE_HS400_1_8V | \
>>  					 EXT_CSD_CARD_TYPE_HS400_1_2V)
>> +#define EXT_CSD_CARD_TYPE_HS400ES	(1<<8)	/* Card can run at HS400ES */
>>
>>  #define EXT_CSD_BUS_WIDTH_1	0	/* Card is in 1 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_4	1	/* Card is in 4 bit mode */
>>  #define EXT_CSD_BUS_WIDTH_8	2	/* Card is in 8 bit mode */
>>  #define EXT_CSD_DDR_BUS_WIDTH_4	5	/* Card is in 4 bit DDR mode */
>>  #define EXT_CSD_DDR_BUS_WIDTH_8	6	/* Card is in 8 bit DDR mode */
>> +#define EXT_CSD_BUS_WIDTH_STROBE BIT(7)	/* Enhanced strobe mode */
>>
>>  #define EXT_CSD_TIMING_BC	0	/* Backwards compatility */
>>  #define EXT_CSD_TIMING_HS	1	/* High speed */
>>
>
>
>
>


-- 
Best Regards
Shawn Lin



From wenrui.li at rock-chips.com  Thu May 26 23:48:41 2016
From: wenrui.li at rock-chips.com (Wenrui Li)
Date: Fri, 27 May 2016 14:48:41 +0800
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <9836736.6VjP1ug4kE@wuerfel>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
 <9836736.6VjP1ug4kE@wuerfel>
Message-ID: <5747EDC9.2080603@rock-chips.com>

Hi,

On 2016/5/24 21:03, Arnd Bergmann wrote:
> On Friday, May 20, 2016 6:29:16 PM CEST Shawn Lin wrote:
>
>> +static int rockchip_pcie_wr_own_conf(struct rockchip_pcie_port *pp,
>> +				     int where, int size, u32 val)
>> +{
>> +	u32 tmp;
>> +	int offset;
>> +
>> +	offset = (where & (~0x3));
>> +	tmp = readl(pp->apb_base + PCIE_RC_CONFIG_BASE + offset);
>> +	if (size == 4) {
>> +		writel(val, pp->apb_base + PCIE_RC_CONFIG_BASE + where);
>> +	} else if (size == 2) {
>> +		if (where & 0x2)
>> +			tmp = ((tmp & 0xffff) | (val << 16));
>> +		else
>> +			tmp = ((tmp & 0xffff0000) | val);
>> +
>> +		writel(tmp, pp->apb_base + PCIE_RC_CONFIG_BASE + offset);
>> +	} else if (size == 1) {
>> +		if ((where & 0x3) == 0)
>> +			tmp = ((tmp & (~0xff)) | val);
>> +		else if ((where & 0x3) == 1)
>> +			tmp = ((tmp & (~0xff00)) | (val << 8));
>> +		else if ((where & 0x3) == 2)
>> +			tmp = ((tmp & (~0xff0000)) | (val << 16));
>> +		else if ((where & 0x3) == 3)
>> +			tmp = ((tmp & (~0xff000000)) | (val << 24));
>> +
>> +		writel(tmp, pp->apb_base + PCIE_RC_CONFIG_BASE + offset);
>> +	} else {
>> +		return PCIBIOS_BAD_REGISTER_NUMBER;
>> +	}
>> +	return PCIBIOS_SUCCESSFUL;
>> +}
>
> Why can't you access the individual sub-word registers here?

Our soc not support byte and word write in these region. so we have to 
use writel() to write these registers.

>
>> +
>> +static int rockchip_pcie_rd_other_conf(struct rockchip_pcie_port *pp,
>> +				       struct pci_bus *bus, u32 devfn,
>> +				       int where, int size, u32 *val)
>> +{
>> +	u32 busdev;
>> +
>> +	busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
>> +				PCI_FUNC(devfn), where);
>> +
>> +	if (busdev & (size - 1)) {
>> +		*val = 0;
>> +		return PCIBIOS_BAD_REGISTER_NUMBER;
>> +	}
>> +
>> +	if (size == 4) {
>> +		*val = readl(pp->reg_base + busdev);
>> +	} else if (size == 2) {
>> +		*val = readw(pp->reg_base + busdev);
>> +	} else if (size == 1) {
>> +		*val = readb(pp->reg_base + busdev);
>> +	} else {
>> +		*val = 0;
>> +		return PCIBIOS_BAD_REGISTER_NUMBER;
>> +	}
>> +	return PCIBIOS_SUCCESSFUL;
>> +}
>> +
>
> This looks like the normal ECAM operations, you could just call those.

I read ECAM reference code, I found it not support ioremap config space 
for each bus individually on 64-bit systems. Our soc is 64-bit system, 
and bus0 config space base address is 0xfda00000, bus1 base address is 
0xf8100000. So I think it is not normal ECAM operations, I do not know 
if I have understood correctly?

>
>> +	while (time_before(jiffies, timeout)) {
>> +		regmap_read(port->grf, port->pcie_status, &status);
>> +		if ((status & (1 << 9))) {
>> +			dev_info(port->dev, "pll locked!\n");
>> +			err = 0;
>> +			break;
>> +		}
>> +	}
>
> Maybe add an msleep(1) here to avoid busy-looping?

Yeah, its a good suggestion.

>
>
>> +	for (reg_no = 0; reg_no < (port->mem_size >> 20); reg_no++) {
>> +		err = rockchip_pcie_prog_ob_atu(port, reg_no + 1,
>> +						AXI_WRAPPER_MEM_WRITE,
>> +						20 - 1,
>> +						port->mem_bus_addr +
>> +							(reg_no << 20),
>> +						0);
>> +		if (err) {
>> +			dev_err(dev, "Program RC outbound atu failed\n");
>> +			return err;
>> +		}
>> +	}
>
> What if there is more than one outbound memory window, e.g. prefetchable
> and non-prefetchable?
>
> Where do you set the I/O window?


Yeah, our soc support these outbound windows, we will support these 
windows next patch.

>
>> +	err = rockchip_pcie_prog_ib_atu(port, 2, 32 - 1, 0x0, 0);
>> +	if (err) {
>> +		dev_err(dev, "Program RC inbound atu failed\n");
>> +		return err;
>> +	}
>
> And this doesn't seem to reflect the DMA ranges.

Our soc support all the ram region use as DMA zone. SO I set all the 32 
bits bypass for the inbound ATS.

>
>> +
>> +	port->root_bus_nr = port->busn->start;
>> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
>> +		bus = pci_scan_root_bus_msi(port->dev, port->root_bus_nr,
>> +					    &rockchip_pcie_ops, port, &res,
>> +					    port->msi);
>> +	} else {
>> +		bus = pci_scan_root_bus(&pdev->dev, 0,
>> +					&rockchip_pcie_ops, port, &res);
>
>
> PCI_MSI is selected unconditionally from Kconfig for this driver, so no
> need for the compile-time check here.

Yeah, we will delete the compile-time check in next patch.

>
>> +
>> +static int rockchip_pcie_remove(struct platform_device *pdev)
>> +{
>> +	struct rockchip_pcie_port *port = platform_get_drvdata(pdev);
>> +
>> +	clk_disable_unprepare(port->hclk_pcie);
>> +	clk_disable_unprepare(port->aclk_perf_pcie);
>> +	clk_disable_unprepare(port->aclk_pcie);
>> +	clk_disable_unprepare(port->clk_pciephy_ref);
>> +
>> +	return 0;
>> +}
>
> You don't seem to remove the child devices here. Have you tried unloading the module?
>

I don't seem the remove function in other pcie host driver. I think this 
function could be deleted.

> 	Arnd
>
>
>
>
>

Best Regards
Wenrui Li



From bharat.kumar.gogada at xilinx.com  Fri May 27 00:13:29 2016
From: bharat.kumar.gogada at xilinx.com (Bharat Kumar Gogada)
Date: Fri, 27 May 2016 07:13:29 +0000
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <5747EDC9.2080603@rock-chips.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
 <9836736.6VjP1ug4kE@wuerfel> <5747EDC9.2080603@rock-chips.com>
Message-ID: <8520D5D51A55D047800579B094147198258AF22F@XAP-PVEXMBX01.xlnx.xilinx.com>

> >
> >> +
> >> +static int rockchip_pcie_rd_other_conf(struct rockchip_pcie_port *pp,
> >> +				       struct pci_bus *bus, u32 devfn,
> >> +				       int where, int size, u32 *val)
> >> +{
> >> +	u32 busdev;
> >> +
> >> +	busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
> >> +				PCI_FUNC(devfn), where);
> >> +
> >> +	if (busdev & (size - 1)) {
> >> +		*val = 0;
> >> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> >> +	}
> >> +
> >> +	if (size == 4) {
> >> +		*val = readl(pp->reg_base + busdev);
> >> +	} else if (size == 2) {
> >> +		*val = readw(pp->reg_base + busdev);
> >> +	} else if (size == 1) {
> >> +		*val = readb(pp->reg_base + busdev);
> >> +	} else {
> >> +		*val = 0;
> >> +		return PCIBIOS_BAD_REGISTER_NUMBER;
> >> +	}
> >> +	return PCIBIOS_SUCCESSFUL;
> >> +}
> >> +
> >
> > This looks like the normal ECAM operations, you could just call those.
> 
> I read ECAM reference code, I found it not support ioremap config space
> for each bus individually on 64-bit systems. Our soc is 64-bit system,
> and bus0 config space base address is 0xfda00000, bus1 base address is
> 0xf8100000. So I think it is not normal ECAM operations, I do not know
> if I have understood correctly?
> 
Hi,

I think Arnd was suggesting to use generic config read/write calls, pci_generic_config_read/pci_generic_config_write
which does above functionality.

Bharat 


From kever.yang at rock-chips.com  Fri May 27 00:38:01 2016
From: kever.yang at rock-chips.com (Kever Yang)
Date: Fri, 27 May 2016 15:38:01 +0800
Subject: [PATCH 0/6] Rockchip Type-C and DispplayPort driver
In-Reply-To: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
Message-ID: <5747F959.7010101@rock-chips.com>

Hi Chris,

On 05/27/2016 02:02 PM, Chris Zhong wrote:
> Hi all
>
> This series patch is for rockchip Type-C phy and DisplayPort controller
> driver.
>
> The USB Type-C PHY is designed to support the USB3 and DP applications.
> The PHY basically has two main components: USB3 and DisplyPort. USB3
> operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2
> data rates. The Type-C cable orientation detection and Power Delivery
> (PD) is accomplished using a PD PHY or a exernal PD chip.
>
> The DP controller is compliant with DisplayPort Specification,
> Version 1.3, This IP is compatible with the rockchip type-c PHY IP.
> There is a uCPU in DP controller, it need a firmware to work, please
> put the firmware file to /lib/firmware/cdn/dptx.bin. The uCPU in charge
> of aux communication and link training, the host use mailbox to
> communicate with the ucpu.
>
> The PHY driver has register a notification, to get the alt mode from PD,
> the PD driver need call the tcphy_notifier_call_chain to notify PHY and
> DP controller.
For the notification for the port status change from PD, I think we can
use the extcon class, pls reference the code in drivers/extcon/ for usage.

Thanks,
- Kever
>
> This series is based on Mark Yao's branch:
> https://github.com/markyzq/kernel-drm-rockchip/tree/drm-rockchip-next-2016-05-23
>
> I test this patches on the rk3399-evb board, with a fusb302 driver,
> this branch has no rk3399.dtsi, so the patch about dts is not included
> in this series.
>
>
>
> Chris Zhong (6):
>    phy: Add USB Type-C PHY driver for rk3399
>    Documentation: bindings: add dt doc for Rockchip USB Type-C PHY
>    drm/rockchip: vop: add cdn DP support for rk3399
>    Documentation: bindings: add dt documentation for cdn DP controller
>    ASoC: cdn-dp: Add cdn DP codec driver
>    ASoC: rockchip: Add machine driver for cdn dp codec
>
>   .../bindings/display/rockchip/cdn-dp-rockchip.txt  |  57 ++
>   .../devicetree/bindings/phy/phy-rockchip-typec.txt |  55 ++
>   .../bindings/sound/rockchip-cdn-dp-audio.txt       |  12 +
>   drivers/gpu/drm/rockchip/Kconfig                   |   9 +
>   drivers/gpu/drm/rockchip/Makefile                  |   1 +
>   drivers/gpu/drm/rockchip/cdn-dp-core.c             | 620 ++++++++++++++++
>   drivers/gpu/drm/rockchip/cdn-dp-core.h             |  95 +++
>   drivers/gpu/drm/rockchip/cdn-dp-reg.c              | 730 ++++++++++++++++++
>   drivers/gpu/drm/rockchip/cdn-dp-reg.h              | 404 ++++++++++
>   drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |   9 +-
>   drivers/gpu/drm/rockchip/rockchip_drm_vop.h        |   2 +
>   drivers/gpu/drm/rockchip/rockchip_vop_reg.c        |   2 +
>   drivers/phy/Kconfig                                |   7 +
>   drivers/phy/Makefile                               |   1 +
>   drivers/phy/phy-rockchip-typec.c                   | 823 +++++++++++++++++++++
>   include/sound/cdn-dp-audio.h                       |  51 ++
>   sound/soc/codecs/Kconfig                           |   3 +
>   sound/soc/codecs/Makefile                          |   2 +
>   sound/soc/codecs/cdn-dp-audio.c                    | 246 ++++++
>   sound/soc/rockchip/Kconfig                         |   9 +
>   sound/soc/rockchip/Makefile                        |   2 +
>   sound/soc/rockchip/rockchip-cdn-dp-audio.c         | 167 +++++
>   22 files changed, 3306 insertions(+), 1 deletion(-)
>   create mode 100644 Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt
>   create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
>   create mode 100644 Documentation/devicetree/bindings/sound/rockchip-cdn-dp-audio.txt
>   create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.c
>   create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.h
>   create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c
>   create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.h
>   create mode 100644 drivers/phy/phy-rockchip-typec.c
>   create mode 100644 include/sound/cdn-dp-audio.h
>   create mode 100644 sound/soc/codecs/cdn-dp-audio.c
>   create mode 100644 sound/soc/rockchip/rockchip-cdn-dp-audio.c
>




From kever.yang at rock-chips.com  Fri May 27 01:05:54 2016
From: kever.yang at rock-chips.com (Kever Yang)
Date: Fri, 27 May 2016 16:05:54 +0800
Subject: [PATCH 1/6] phy: Add USB Type-C PHY driver for rk3399
In-Reply-To: <1464328939-8073-2-git-send-email-zyw@rock-chips.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
 <1464328939-8073-2-git-send-email-zyw@rock-chips.com>
Message-ID: <5747FFE2.9070302@rock-chips.com>

Hi Chris,

On 05/27/2016 02:02 PM, Chris Zhong wrote:
> Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB
> Type-C PHY is designed to support the USB3 and DP applications. The
> PHY basically has two main components: USB3 and DisplyPort. USB3
> operates in SuperSpeed mode and the DP can operate at RBR, HBR and
> HBR2 data rates.
>
> Signed-off-by: Chris Zhong <zyw at rock-chips.com>
> ---
>
>   drivers/phy/Kconfig              |   7 +
>   drivers/phy/Makefile             |   1 +
>   drivers/phy/phy-rockchip-typec.c | 823 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 831 insertions(+)
>   create mode 100644 drivers/phy/phy-rockchip-typec.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 26566db..dc388a3d 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -351,6 +351,13 @@ config PHY_ROCKCHIP_DP
>   	help
>   	  Enable this to support the Rockchip Display Port PHY.
>   
> +config PHY_ROCKCHIP_TYPEC
> +	tristate "Rockchip TYPEC PHY Driver"
> +	depends on ARCH_ROCKCHIP && OF
> +	select GENERIC_PHY
> +	help
> +	  Enable this to support the Rockchip USB TYPEC PHY.
> +
>   config PHY_ST_SPEAR1310_MIPHY
>   	tristate "ST SPEAR1310-MIPHY driver"
>   	select GENERIC_PHY
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 24596a9..91fa413 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -39,6 +39,7 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
>   obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
>   obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
>   obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
> +obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
>   obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
>   obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)	+= phy-spear1310-miphy.o
>   obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
> diff --git a/drivers/phy/phy-rockchip-typec.c b/drivers/phy/phy-rockchip-typec.c
> new file mode 100644
> index 0000000..6609cfb
> --- /dev/null
> +++ b/drivers/phy/phy-rockchip-typec.c
> @@ -0,0 +1,823 @@
> +/*
> + * Rockchip usb3 PHY driver
> + *
> + * Copyright (C) 2016 Kever Yang <kever.yang at rock-chips.com>
> + *                    Chris Zhong <zyw at rock-chips.com>
> + * Copyright (C) 2016 ROCKCHIP, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/delay.h>
> +#include <linux/phy/phy-rockchip-typec.h>
> +
> +#define ADDR_ADJ			2
> +#define CMN_SSM_BANDGAP			(0x21 << ADDR_ADJ)
> +#define CMN_SSM_BIAS			(0x22 << ADDR_ADJ)
> +#define CMN_PLLSM0_PLLEN		(0x29 << ADDR_ADJ)
> +#define CMN_PLLSM0_PLLPRE		(0x2a << ADDR_ADJ)
> +#define CMN_PLLSM0_PLLVREF		(0x2b << ADDR_ADJ)
> +#define CMN_PLLSM0_PLLLOCK		(0x2c << ADDR_ADJ)
> +#define CMN_PLLSM1_PLLEN		(0x31 << ADDR_ADJ)
> +#define CMN_PLLSM1_PLLPRE		(0x32 << ADDR_ADJ)
> +#define CMN_PLLSM1_PLLVREF		(0x33 << ADDR_ADJ)
> +#define CMN_PLLSM1_PLLLOCK		(0x34 << ADDR_ADJ)
> +#define CMN_PLLSM1_USER_DEF_CTRL	(0x37 << ADDR_ADJ)
> +#define CMN_ICAL_OVRD			(0xc1 << ADDR_ADJ)
> +#define CMN_PLL0_VCOCAL_OVRD		(0x83 << ADDR_ADJ)
> +#define CMN_PLL0_VCOCAL_INIT		(0x84 << ADDR_ADJ)
> +#define CMN_PLL0_VCOCAL_ITER		(0x85 << ADDR_ADJ)
> +#define CMN_PLL0_LOCK_REFCNT_START	(0x90 << ADDR_ADJ)
> +#define CMN_PLL0_LOCK_PLLCNT_START	(0x92 << ADDR_ADJ)
> +#define CMN_PLL0_LOCK_PLLCNT_THR	(0x93 << ADDR_ADJ)
> +#define CMN_PLL0_INTDIV			(0x94 << ADDR_ADJ)
> +#define CMN_PLL0_FRACDIV		(0x95 << ADDR_ADJ)
> +#define CMN_PLL0_HIGH_THR		(0x96 << ADDR_ADJ)
> +#define CMN_PLL0_DSM_DIAG		(0x97 << ADDR_ADJ)
> +#define CMN_PLL0_SS_CTRL1		(0x98 << ADDR_ADJ)
> +#define CMN_PLL0_SS_CTRL2		(0x99 << ADDR_ADJ)
> +#define CMN_PLL1_VCOCAL_START		(0xa1 << ADDR_ADJ)
> +#define CMN_PLL1_VCOCAL_OVRD		(0xa3 << ADDR_ADJ)
> +#define CMN_PLL1_VCOCAL_INIT		(0xa4 << ADDR_ADJ)
> +#define CMN_PLL1_VCOCAL_ITER		(0xa5 << ADDR_ADJ)
> +#define CMN_PLL1_LOCK_REFCNT_START	(0xb0 << ADDR_ADJ)
> +#define CMN_PLL1_LOCK_PLLCNT_START	(0xb2 << ADDR_ADJ)
> +#define CMN_PLL1_LOCK_PLLCNT_THR	(0xb3 << ADDR_ADJ)
> +#define CMN_PLL1_INTDIV			(0xb4 << ADDR_ADJ)
> +#define CMN_PLL1_FRACDIV		(0xb5 << ADDR_ADJ)
> +#define CMN_PLL1_HIGH_THR		(0xb6 << ADDR_ADJ)
> +#define CMN_PLL1_DSM_DIAG		(0xb7 << ADDR_ADJ)
> +#define CMN_PLL1_SS_CTRL1		(0xb8 << ADDR_ADJ)
> +#define CMN_PLL1_SS_CTRL2		(0xb9 << ADDR_ADJ)
> +#define CMN_RXCAL_OVRD			(0xd1 << ADDR_ADJ)
> +#define CMN_TXPUCAL_CTRL		(0xe0 << ADDR_ADJ)
> +#define CMN_TXPUCAL_OVRD		(0xe1 << ADDR_ADJ)
> +#define CMN_TXPDCAL_OVRD		(0xf1 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_FBH_OVRD		(0x1c0 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_FBL_OVRD		(0x1c1 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_OVRD		(0x1c2 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_V2I_TUNE		(0x1c5 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_CP_TUNE		(0x1c6 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_LF_PROG		(0x1c7 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_FBH_OVRD		(0x1d0 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_FBL_OVRD		(0x1d1 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_OVRD		(0x1d2 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_V2I_TUNE		(0x1d5 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_CP_TUNE		(0x1d6 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_LF_PROG		(0x1d7 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_PTATIS_TUNE1	(0x1d8 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_PTATIS_TUNE2	(0x1d9 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_INCLK_CTRL	(0x1da << ADDR_ADJ)
> +#define CMN_DIAG_HSCLK_SEL		(0x1e0 << ADDR_ADJ)
> +
> +#define XCVR_PSM_RCTRL(n)		((0x4001 | (n << 9)) << ADDR_ADJ)
> +#define XCVR_PSM_CAL_TMR(n)		((0x4002 | (n << 9)) << ADDR_ADJ)
> +#define XCVR_PSM_A0IN_TMR(n)		((0x4003 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_CAL_SCLR_MULT(n)	((0x4047 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_CPOST_MULT_00(n)	((0x404c | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_CPOST_MULT_01(n)	((0x404d | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_CPOST_MULT_10(n)	((0x404e | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_CPOST_MULT_11(n)	((0x404f | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_000(n)	((0x4050 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_001(n)	((0x4051 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_010(n)	((0x4052 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_011(n)	((0x4053 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_100(n)	((0x4054 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_101(n)	((0x4055 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_110(n)	((0x4056 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_111(n)	((0x4057 | (n << 9)) << ADDR_ADJ)
> +#define XCVR_DIAG_PLLDRC_CTRL(n)	((0x40e0 | (n << 9)) << ADDR_ADJ)
> +#define XCVR_DIAG_BIDI_CTRL(n)		((0x40e8 | (n << 9)) << ADDR_ADJ)
> +#define XCVR_DIAG_LANE_FCM_EN_MGN(n)	((0x40f2 | (n << 9)) << ADDR_ADJ)
> +#define TX_PSC_A0(n)			((0x4100 | (n << 9)) << ADDR_ADJ)
> +#define TX_PSC_A1(n)			((0x4101 | (n << 9)) << ADDR_ADJ)
> +#define TX_PSC_A2(n)			((0x4102 | (n << 9)) << ADDR_ADJ)
> +#define TX_PSC_A3(n)			((0x4103 | (n << 9)) << ADDR_ADJ)
> +#define TX_RCVDET_CTRL(n)		((0x4120 | (n << 9)) << ADDR_ADJ)
> +#define TX_RCVDET_EN_TMR(n)		((0x4122 | (n << 9)) << ADDR_ADJ)
> +#define TX_RCVDET_ST_TMR(n)		((0x4123 | (n << 9)) << ADDR_ADJ)
> +#define TX_DIAG_TX_DRV(n)		((0x41e1 | (n << 9)) << ADDR_ADJ)
> +#define TX_DIAG_BGREF_PREDRV_DELAY	(0x41e7 << ADDR_ADJ)
> +#define TX_ANA_CTRL_REG_1		(0x5020 << ADDR_ADJ)
> +#define TX_ANA_CTRL_REG_2		(0x5021 << ADDR_ADJ)
> +#define TXDA_COEFF_CALC_CTRL		(0x5022 << ADDR_ADJ)
> +#define TX_DIG_CTRL_REG_2		(0x5024 << ADDR_ADJ)
> +#define TXDA_CYA_AUXDA_CYA		(0x5025 << ADDR_ADJ)
> +#define TX_ANA_CTRL_REG_3		(0x5026 << ADDR_ADJ)
> +#define TX_ANA_CTRL_REG_4		(0x5027 << ADDR_ADJ)
> +#define TX_ANA_CTRL_REG_5		(0x5029 << ADDR_ADJ)
> +
> +#define RX_PSC_A0(n)			((0x8000 | (n << 9)) << ADDR_ADJ)
> +#define RX_PSC_A1(n)			((0x8001 | (n << 9)) << ADDR_ADJ)
> +#define RX_PSC_A2(n)			((0x8002 | (n << 9)) << ADDR_ADJ)
> +#define RX_PSC_A3(n)			((0x8003 | (n << 9)) << ADDR_ADJ)
> +#define RX_PSC_CAL(n)			((0x8006 | (n << 9)) << ADDR_ADJ)
> +#define RX_PSC_RDY(n)			((0x8007 | (n << 9)) << ADDR_ADJ)
> +#define RX_IQPI_ILL_CAL_OVRD		(0x8023 << ADDR_ADJ)
> +#define RX_EPI_ILL_CAL_OVRD		(0x8033 << ADDR_ADJ)
> +#define RX_SDCAL0_OVRD			(0x8041 << ADDR_ADJ)
> +#define RX_SDCAL1_OVRD			(0x8049 << ADDR_ADJ)
> +#define RX_SLC_INIT			(0x806d << ADDR_ADJ)
> +#define RX_SLC_RUN			(0x806e << ADDR_ADJ)
> +#define RX_CDRLF_CNFG2			(0x8081 << ADDR_ADJ)
> +#define RX_SIGDET_HL_FILT_TMR(n)	((0x8090 | (n << 9)) << ADDR_ADJ)
> +#define RX_SLC_IOP0_OVRD		(0x8101 << ADDR_ADJ)
> +#define RX_SLC_IOP1_OVRD		(0x8105 << ADDR_ADJ)
> +#define RX_SLC_QOP0_OVRD		(0x8109 << ADDR_ADJ)
> +#define RX_SLC_QOP1_OVRD		(0x810d << ADDR_ADJ)
> +#define RX_SLC_EOP0_OVRD		(0x8111 << ADDR_ADJ)
> +#define RX_SLC_EOP1_OVRD		(0x8115 << ADDR_ADJ)
> +#define RX_SLC_ION0_OVRD		(0x8119 << ADDR_ADJ)
> +#define RX_SLC_ION1_OVRD		(0x811d << ADDR_ADJ)
> +#define RX_SLC_QON0_OVRD		(0x8121 << ADDR_ADJ)
> +#define RX_SLC_QON1_OVRD		(0x8125 << ADDR_ADJ)
> +#define RX_SLC_EON0_OVRD		(0x8129 << ADDR_ADJ)
> +#define RX_SLC_EON1_OVRD		(0x812d << ADDR_ADJ)
> +#define RX_SLC_IEP0_OVRD		(0x8131 << ADDR_ADJ)
> +#define RX_SLC_IEP1_OVRD		(0x8135 << ADDR_ADJ)
> +#define RX_SLC_QEP0_OVRD		(0x8139 << ADDR_ADJ)
> +#define RX_SLC_QEP1_OVRD		(0x813d << ADDR_ADJ)
> +#define RX_SLC_EEP0_OVRD		(0x8141 << ADDR_ADJ)
> +#define RX_SLC_EEP1_OVRD		(0x8145 << ADDR_ADJ)
> +#define RX_SLC_IEN0_OVRD		(0x8149 << ADDR_ADJ)
> +#define RX_SLC_IEN1_OVRD		(0x814d << ADDR_ADJ)
> +#define RX_SLC_QEN0_OVRD		(0x8151 << ADDR_ADJ)
> +#define RX_SLC_QEN1_OVRD		(0x8155 << ADDR_ADJ)
> +#define RX_SLC_EEN0_OVRD		(0x8159 << ADDR_ADJ)
> +#define RX_SLC_EEN1_OVRD		(0x815d << ADDR_ADJ)
> +#define RX_DIAG_SIGDET_TUNE(n)		((0x81dc | (n << 9)) << ADDR_ADJ)
> +#define RX_DIAG_SC2C_DELAY		(0x81e1 << ADDR_ADJ)
> +
> +#define PMA_LANE_CFG			(0xc000 << ADDR_ADJ)
> +#define PIPE_CMN_CTRL1			(0xc001 << ADDR_ADJ)
> +#define PIPE_CMN_CTRL2			(0xc002 << ADDR_ADJ)
> +#define PIPE_COM_LOCK_CFG1		(0xc003 << ADDR_ADJ)
> +#define PIPE_COM_LOCK_CFG2		(0xc004 << ADDR_ADJ)
> +#define PIPE_RCV_DET_INH		(0xc005 << ADDR_ADJ)
> +#define DP_MODE_CTL			(0xc008 << ADDR_ADJ)
> +#define DP_CLK_CTL			(0xc009 << ADDR_ADJ)
> +#define STS				(0xc00F << ADDR_ADJ)
> +#define PHY_ISO_CMN_CTRL		(0xc010 << ADDR_ADJ)
> +#define PHY_DP_TX_CTL			(0xc408 << ADDR_ADJ)
> +#define PMA_CMN_CTRL1			(0xc800 << ADDR_ADJ)
> +#define PHY_PMA_ISO_CMN_CTRL		(0xc810 << ADDR_ADJ)
> +#define PHY_ISOLATION_CTRL		(0xc81f << ADDR_ADJ)
> +#define PHY_PMA_ISO_XCVR_CTRL(n)	((0xcc11 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_LINK_MODE(n)	((0xcc12 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_PWRST_CTRL(n)	((0xcc13 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_TX_DATA_LO(n)	((0xcc14 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_TX_DATA_HI(n)	((0xcc15 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_RX_DATA_LO(n)	((0xcc16 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_RX_DATA_HI(n)	((0xcc17 | (n << 6)) << ADDR_ADJ)
> +#define TX_BIST_CTRL(n)			((0x4140 | (n << 9)) << ADDR_ADJ)
> +#define TX_BIST_UDDWR(n)		((0x4141 | (n << 9)) << ADDR_ADJ)
> +
> +#define GRF_SOC_CON26			0x6268
> +#define UPHY_DP_SEL			BIT(3)
> +#define UPHY_DP_SEL_MASK		BIT(19)
> +#define DPTX_HDP_SEL			(3 << 12)
> +#define DPTX_HDP_SEL_MASK		(3 << 28)
> +
> +#define PHY_MODE_SET_TIMEOUT		1000000
> +
> +#define	MODE_DISCONNECT			1
> +#define	MODE_UFP			2
> +#define	MODE_DFP_USBONLY		3
> +#define	MODE_DFP_DPONLY			4
> +#define	MODE_DFP_USB3DP			5
> +#define	MODE_DFP_USB2DP			6
> +
> +#define PARSE_GRF_REG(TYPE) { \
> +	if (of_find_property(np, "rockchip,usb3phy_"#TYPE, &len)) { \
> +		len /= sizeof(u32);\
> +		ret = of_property_read_u32_array(np, "rockchip,usb3phy_" #TYPE,\
> +						 array, len); \
> +		exregs->usb3phy_##TYPE = array[0]; \
> +		exregs->usb3phy_##TYPE##_shift = array[1]; \
> +		exregs->usb3phy_##TYPE##_mask = array[2]; \
> +		pr_info("%s property found %s, %x, %d, %d\n", __func__, \
> +			"rockchip,usb3phy_"#TYPE, \
> +			array[0], array[1], array[2]); \
> +	} else { \
> +		pr_info("%s property not found %s\n", __func__, \
> +			"rockchip,usb3phy_" #TYPE); \
> +	} \
> +}
> +
> +struct rockchip_typec_phy *rockchip_tcphy;
> +
> +static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy,
> +			  unsigned int num_lanes)
> +{
> +	unsigned int i;
> +
> +	writel(0x830, tcphy->base + PMA_CMN_CTRL1);
> +	for (i = 0; i < num_lanes; i++) {
> +		writel(0x90, tcphy->base + XCVR_DIAG_LANE_FCM_EN_MGN(i));
> +		writel(0x960, tcphy->base + TX_RCVDET_EN_TMR(i));
> +		writel(0x30, tcphy->base + TX_RCVDET_ST_TMR(i));
> +	}
> +}
> +
> +static void tcphy_cfg_usb_pll(struct rockchip_typec_phy *tcphy)
> +{
> +	unsigned int rdata;
> +
> +	rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
> +	writel(rdata & 0xfffc, tcphy->base + CMN_DIAG_HSCLK_SEL);
> +	writel(0xf0, tcphy->base + CMN_PLL0_VCOCAL_INIT);
> +	writel(0x18, tcphy->base + CMN_PLL0_VCOCAL_ITER);
> +	writel(0xd0, tcphy->base + CMN_PLL0_INTDIV);
> +	writel(0x4a4a, tcphy->base + CMN_PLL0_FRACDIV);
> +	writel(0x34, tcphy->base + CMN_PLL0_HIGH_THR);
> +	writel(0x1ee, tcphy->base + CMN_PLL0_SS_CTRL1);
> +	writel(0x7f03, tcphy->base + CMN_PLL0_SS_CTRL2);
> +	writel(0x20, tcphy->base + CMN_PLL0_DSM_DIAG);
> +	writel(0, tcphy->base + CMN_DIAG_PLL0_OVRD);
> +	writel(0, tcphy->base + CMN_DIAG_PLL0_FBH_OVRD);
> +	writel(0, tcphy->base + CMN_DIAG_PLL0_FBL_OVRD);
> +	writel(0x7, tcphy->base + CMN_DIAG_PLL0_V2I_TUNE);
> +	writel(0x45, tcphy->base + CMN_DIAG_PLL0_CP_TUNE);
> +	writel(0x8, tcphy->base + CMN_DIAG_PLL0_LF_PROG);
> +}
> +
> +static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy)
> +{
> +	unsigned int rdata;
> +
> +	writel(0x2405, tcphy->base + DP_CLK_CTL);
> +
> +	rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
> +	rdata = (rdata & 0xffcf) | 0x30;
> +	writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL);
> +	writel(0xf0, tcphy->base + CMN_PLL1_VCOCAL_INIT);
> +	writel(0x18, tcphy->base + CMN_PLL1_VCOCAL_ITER);
> +	writel(0x30b9, tcphy->base + CMN_PLL1_VCOCAL_START);
> +	writel(0x21c, tcphy->base + CMN_PLL1_INTDIV);
> +	writel(0, tcphy->base + CMN_PLL1_FRACDIV);
> +	writel(0x5, tcphy->base + CMN_PLL1_HIGH_THR);
> +	writel(0x35, tcphy->base + CMN_PLL1_SS_CTRL1);
> +	writel(0x7f1e, tcphy->base + CMN_PLL1_SS_CTRL2);
> +	writel(0x20, tcphy->base + CMN_PLL1_DSM_DIAG);
> +	writel(0, tcphy->base + CMN_PLLSM1_USER_DEF_CTRL);
> +	writel(0, tcphy->base + CMN_DIAG_PLL1_OVRD);
> +	writel(0, tcphy->base + CMN_DIAG_PLL1_FBH_OVRD);
> +	writel(0, tcphy->base + CMN_DIAG_PLL1_FBL_OVRD);
> +	writel(0x6, tcphy->base + CMN_DIAG_PLL1_V2I_TUNE);
> +	writel(0x45, tcphy->base + CMN_DIAG_PLL1_CP_TUNE);
> +	writel(0x8, tcphy->base + CMN_DIAG_PLL1_LF_PROG);
> +	writel(0x100, tcphy->base + CMN_DIAG_PLL1_PTATIS_TUNE1);
> +	writel(0x7, tcphy->base + CMN_DIAG_PLL1_PTATIS_TUNE2);
> +	writel(0x4, tcphy->base + CMN_DIAG_PLL1_INCLK_CTRL);
> +}
> +
> +static void tcphy_tx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
> +				  unsigned int lane)
> +{
> +	writel(0x7799, tcphy->base + TX_PSC_A0(lane));
> +	writel(0x7798, tcphy->base + TX_PSC_A1(lane));
> +	writel(0x5098, tcphy->base + TX_PSC_A2(lane));
> +	writel(0x5098, tcphy->base + TX_PSC_A3(lane));
> +	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
> +	writel(0xbf, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
> +}
> +
> +static void tcphy_rx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
> +				  unsigned int lane)
> +{
> +	writel(0xa6fd, tcphy->base + RX_PSC_A0(lane));
> +	writel(0xa6fd, tcphy->base + RX_PSC_A1(lane));
> +	writel(0xa410, tcphy->base + RX_PSC_A2(lane));
> +	writel(0x2410, tcphy->base + RX_PSC_A3(lane));
> +	writel(0x23ff, tcphy->base + RX_PSC_CAL(lane));
> +	writel(0x13, tcphy->base + RX_SIGDET_HL_FILT_TMR(lane));
> +	writel(0x1004, tcphy->base + RX_DIAG_SIGDET_TUNE(lane));
> +	writel(0x2010, tcphy->base + RX_PSC_RDY(lane));
> +	writel(0xfb, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
> +}
> +
> +static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy,
> +			      unsigned int lane)
> +{
> +	unsigned int rdata;
> +
> +	writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane));
> +	writel(0x6799, tcphy->base + TX_PSC_A0(lane));
> +	writel(0x6798, tcphy->base + TX_PSC_A1(lane));
> +	writel(0x98, tcphy->base + TX_PSC_A2(lane));
> +	writel(0x98, tcphy->base + TX_PSC_A3(lane));
> +	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
> +	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_001(lane));
> +	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_010(lane));
> +	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_011(lane));
> +	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_100(lane));
> +	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_101(lane));
> +	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_110(lane));
> +	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_111(lane));
> +
> +	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_10(lane));
> +	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_01(lane));
> +	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_00(lane));
> +	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_11(lane));
> +
> +	writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane));
> +	writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane));
> +
> +	rdata = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
> +	rdata = (rdata & 0x8fff) | 0x6000;
> +	writel(rdata, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
> +}
> +
> +static void tcphy_cfg_pin_assign(struct rockchip_typec_phy *tcphy)
> +{
> +	switch (tcphy->map) {
> +	case PIN_MAP_A:
> +		writel(0x19d5, tcphy->base + PMA_LANE_CFG);
> +		break;
> +	case PIN_MAP_B:
> +		writel(0x1500, tcphy->base + PMA_LANE_CFG);
> +		break;
> +	case PIN_MAP_C:
> +	case PIN_MAP_E:
> +		writel(0x51d9, tcphy->base + PMA_LANE_CFG);
> +		break;
> +	case PIN_MAP_D:
> +	case PIN_MAP_F:
> +		writel(0x5100, tcphy->base + PMA_LANE_CFG);
> +		break;
> +	};
> +}
> +
> +static void tcphy_cfg_lanes(struct rockchip_typec_phy *tcphy,
> +			    unsigned int link_cfg)
> +{
> +	unsigned int i;
> +
> +	/* PMA lane configuration DP or USB3 */
> +	for (i = 0; i < 4; i++) {
> +		if ((link_cfg >> i) & 0x1) {
> +			tcphy_dp_cfg_lane(tcphy, i);
> +		} else {
> +			/*
> +			 * lan0 TX and lan1 RX for USB3 Normal direction
> +			 * lan3 TX and lan2 RX for USB3 Flip direction
> +			 */
> +			if ((i == 0) | (i == 3))
> +				tcphy_tx_usb_cfg_lane(tcphy, i);
> +			else
> +				tcphy_rx_usb_cfg_lane(tcphy, i);
> +		}
> +	}
> +}
> +
> +static void tcphy_cfg_flip_set(struct rockchip_typec_phy *tcphy)
> +{
> +	regmap_write(tcphy->grf_regs,
> +		     tcphy->exregs.usb3phy_con0,
> +		     tcphy->flip | BIT(16));
> +
> +	tcphy_cfg_24m(tcphy, 0x4);
> +
> +	if (tcphy->mode == MODE_UFP ||
> +	    tcphy->mode == MODE_DFP_USBONLY ||
> +	    tcphy->mode == MODE_DFP_USB3DP)
> +		tcphy_cfg_usb_pll(tcphy);
> +
> +	if (tcphy->mode == MODE_DFP_DPONLY ||
> +	    tcphy->mode == MODE_DFP_USB2DP ||
> +	    tcphy->mode == MODE_DFP_USB3DP)
> +		tcphy_cfg_dp_pll(tcphy);
> +
> +	if (tcphy->mode == MODE_DFP_DPONLY || tcphy->mode == MODE_DFP_USB2DP)
> +		tcphy_cfg_lanes(tcphy, 0xf);
> +	else if (tcphy->flip)
> +		tcphy_cfg_lanes(tcphy, 0x3);
> +	else
> +		tcphy_cfg_lanes(tcphy, 0xc);
> +}
> +
> +static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
> +{
> +	int rdata, rdata2, val;
> +
> +	rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
> +	rdata2 = readl(tcphy->base + CMN_TXPUCAL_CTRL);
> +
> +	rdata = rdata & 0xdfff;
> +	writel(rdata, tcphy->base + TX_ANA_CTRL_REG_1);
> +
> +	rdata = readl(tcphy->base + TX_DIG_CTRL_REG_2);
> +	rdata = rdata & 0xffc0;
> +	rdata2 = rdata2 & 0x3f;
> +	rdata  = rdata | rdata2;
> +	writel(rdata, tcphy->base + TX_DIG_CTRL_REG_2);
> +	usleep_range(1000, 2000);
> +
> +	rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
> +	rdata = rdata | 0x2000;
> +	writel(rdata, tcphy->base + TX_ANA_CTRL_REG_1);
> +
> +	usleep_range(150, 200);
> +
> +	writel(0, tcphy->base + PHY_DP_TX_CTL);
> +	writel(0x100, tcphy->base + TX_ANA_CTRL_REG_2);
> +	writel(0x300, tcphy->base + TX_ANA_CTRL_REG_2);
> +	writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
> +	writel(0x2008, tcphy->base + TX_ANA_CTRL_REG_1);
> +	writel(0x2018, tcphy->base + TX_ANA_CTRL_REG_1);
> +	writel(0x30C, tcphy->base + TX_ANA_CTRL_REG_2);
> +	writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
> +	writel(0x1001, tcphy->base + TX_ANA_CTRL_REG_4);
> +	writel(0x2098, tcphy->base + TX_ANA_CTRL_REG_1);
> +	writel(0x2198, tcphy->base + TX_ANA_CTRL_REG_1);
> +	writel(0x30d, tcphy->base + TX_ANA_CTRL_REG_2);
> +	writel(0x30f, tcphy->base + TX_ANA_CTRL_REG_2);
> +
> +	if (tcphy->flip)
> +		writel(0xa078, tcphy->base + TX_ANA_CTRL_REG_1);
> +	else
> +		writel(0xb078, tcphy->base + TX_ANA_CTRL_REG_1);
> +
> +	writel(0x303, tcphy->base + TX_ANA_CTRL_REG_2);
> +	writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
> +	writel(0, tcphy->base + TX_ANA_CTRL_REG_4);
> +	writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
> +	writel(4, tcphy->base + TXDA_COEFF_CALC_CTRL);
> +	writel(0, tcphy->base + TXDA_CYA_AUXDA_CYA);
> +
> +	val = readl(tcphy->base + TX_DIG_CTRL_REG_2);
> +	val |= BIT(15);
> +	writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
> +}
> +
> +static void tcphy_dp_hpd(struct rockchip_typec_phy *tcphy,
> +			 u8 mode)
> +{
> +	/* force hpd */
> +	if (mode)
> +		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
> +			     DPTX_HDP_SEL_MASK | DPTX_HDP_SEL);
> +	else
> +		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
> +			     DPTX_HDP_SEL_MASK);
> +}
> +
> +static int tcphy_usb3_init(struct rockchip_typec_phy *tcphy)
I don't think we should use this name here, this function actually is
waiting for TypeC PHY for usb3 ready instead of do any initialize,
so I prefer to use tcphy_usb3phy_wait4ready().
> +{
> +	int timeout = 0;
> +	int ret, val;
> +
> +	/*wait TCPHY for pipe ready */
> +	while (1) {
> +		ret = regmap_read(tcphy->grf_regs,
> +				  tcphy->exregs.usb3phy_status0, &val);
> +		val >>= tcphy->exregs.usb3phy_status0_shift;
> +		if ((val & 0x1) == 0)
> +			break;
> +
> +		timeout++;
> +		if (timeout > 1000) {
> +			pr_warn("%s wait pipe ready timerout!\n", __func__);
typo for 'timeout' here.
> +			break;
> +		}
> +		usleep_range(10, 20);
> +	}
> +
> +	return 0;
> +}
> +
> +static int tcphy_dp_init(struct rockchip_typec_phy *tcphy)
> +{
> +	int ret, val;
> +
> +	ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
> +				 val, val & BIT(6), 1000, PHY_MODE_SET_TIMEOUT);
> +	if (ret < 0) {
> +		dev_err(tcphy->dev, "failed to wait TCPHY for DP ready\n");
> +		return -EBUSY;
> +	}
> +
> +	tcphy_dp_aux_calibration(tcphy);
> +
> +	if (tcphy->mode == MODE_DFP_USB3DP)
> +		writel(0xc101, tcphy->base + DP_MODE_CTL);
> +	else
> +		writel(0x0101, tcphy->base + DP_MODE_CTL);
> +
> +	ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
> +				 val, val & BIT(4), 1000, PHY_MODE_SET_TIMEOUT);
> +	if (ret < 0) {
> +		dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n");
> +		return -EBUSY;
> +	}
> +
> +	return 0;
> +}
> +
> +static int tcphy_phy_init(struct rockchip_typec_phy *tcphy)
> +{
> +	int ret;
> +	int timeout = 0;
> +
> +	ret = clk_prepare_enable(tcphy->clk_core);
> +	if (ret) {
> +		dev_err(tcphy->dev, "Failed to prepare_enable core clock\n");
> +		return ret;
> +	}
We need to init this clock to 50MHz here.
> +
> +	ret = clk_prepare_enable(tcphy->clk_ref);
> +	if (ret) {
> +		dev_err(tcphy->dev, "Failed to prepare_enable ref clock\n");
> +		return ret;
> +	}
> +
> +	/* select external psm clock */
> +	regmap_write(tcphy->grf_regs, tcphy->exregs.usb3phy_con2,
> +		     BIT(14) | BIT(30));
> +	regmap_write(tcphy->grf_regs, tcphy->exregs.usb3phy_con0, BIT(19));
> +
> +	reset_control_assert(tcphy->phy_rst);
> +	reset_control_assert(tcphy->pipe_rst);
> +	reset_control_assert(tcphy->uphy_rst);
> +
> +	if (tcphy->num == TYPEC_PHY0)
There is no code to init tcphy->num, we can add a dts node for it and
init in probe.
> +		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
> +			     UPHY_DP_SEL_MASK);
> +	else
> +		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
> +			     UPHY_DP_SEL_MASK | UPHY_DP_SEL);
> +
> +	reset_control_deassert(tcphy->uphy_rst);
> +
> +	tcphy_cfg_flip_set(tcphy);
> +
> +	tcphy_cfg_pin_assign(tcphy);
> +
> +	if (tcphy->mode == MODE_DFP_USB3DP)
> +		writel(0xc104, tcphy->base + DP_MODE_CTL);
> +	else if ((tcphy->mode == MODE_DFP_DPONLY) ||
> +		 (tcphy->mode == MODE_DFP_USB2DP))
> +		writel(0x0104, tcphy->base + DP_MODE_CTL);
> +
> +	reset_control_deassert(tcphy->phy_rst);
> +
> +	while (!(readl(tcphy->base + PMA_CMN_CTRL1) & 1)) {
> +		timeout++;
> +		if (timeout > 1000)
> +			break;
> +		usleep_range(10, 20);
> +	}
> +
> +	reset_control_deassert(tcphy->pipe_rst);
> +
> +	return 0;
> +}
> +
> +static int tcphy_phy_deinit(struct rockchip_typec_phy *tcphy)
> +{
> +	clk_disable_unprepare(tcphy->clk_core);
> +	clk_disable_unprepare(tcphy->clk_ref);
> +
> +	return 0;
> +}
> +
> +int tcphy_register_notifier(struct phy *_phy, struct notifier_block *nb)
> +{
> +	struct rockchip_typec_phy *tcphy = phy_get_drvdata(_phy);
> +
> +	return atomic_notifier_chain_register(&tcphy->notifier, nb);
> +}
> +
> +void tcphy_unregister_notifier(struct phy *_phy,
> +			       struct notifier_block *nb)
> +{
> +	struct rockchip_typec_phy *tcphy = phy_get_drvdata(_phy);
> +
> +	atomic_notifier_chain_unregister(&tcphy->notifier, nb);
> +}
> +
> +void tcphy_notifier_call_chain(struct rockchip_typec_phy *x,
> +			       unsigned long val, void *v)
> +{
> +	atomic_notifier_call_chain(&x->notifier, val, v);
> +}
> +EXPORT_SYMBOL_GPL(tcphy_notifier_call_chain);
Try to use extcon instead of create a notifier chain and other code later.

Thanks,
- Kever
> +
> +static int tcphy_pd_event(struct notifier_block *nb,
> +			  unsigned long event, void *priv)
> +{
> +	struct rockchip_typec_phy *tcphy;
> +	int value = *(int *)priv;
> +	u8 is_dp, dfp;
> +
> +	tcphy = container_of(nb, struct rockchip_typec_phy, event_nb);
> +	if (IS_ERR_OR_NULL(tcphy)) {
> +		pr_err("initialization issue");
> +		return -1;
> +	}
> +
> +	tcphy->flip = GET_FLIP(value);
> +	dfp = GET_DFP(value);
> +	is_dp = GET_DP(value);
> +	tcphy->map = GET_PIN_MAP(value);
> +
> +	if (event == 0) {
> +		if (tcphy->mode == MODE_DISCONNECT)
> +			return 0;
> +		tcphy->mode = MODE_DISCONNECT;
> +	} else if (is_dp) {
> +		if (tcphy->map & (PIN_MAP_B | PIN_MAP_D | PIN_MAP_F))
> +			tcphy->mode = MODE_DFP_USB3DP;
> +		else
> +			tcphy->mode = MODE_DFP_DPONLY;
> +	} else if (dfp) {
> +		tcphy->mode = MODE_DFP_USBONLY;
> +	} else {
> +		tcphy->mode = MODE_UFP;
> +	}
> +
> +	schedule_delayed_work_on(0, &tcphy->event_wq, 0);
> +
> +	return 0;
> +}
> +
> +static void tcphy_event_wq(struct work_struct *work)
> +{
> +	struct rockchip_typec_phy *tcphy;
> +
> +	tcphy = container_of(work, struct rockchip_typec_phy, event_wq.work);
> +	if (IS_ERR_OR_NULL(tcphy)) {
> +		pr_err("initialization issue");
> +		return;
> +	}
> +
> +	switch (tcphy->mode) {
> +	case MODE_DISCONNECT:
> +		/* phy enter low power mode */
> +		tcphy_phy_deinit(tcphy);
> +		tcphy_dp_hpd(tcphy, 0);
> +		break;
> +	case MODE_UFP:
> +		tcphy_phy_init(tcphy);
> +		tcphy_usb3_init(tcphy);
> +		tcphy_dp_hpd(tcphy, 0);
> +		break;
> +	case MODE_DFP_USBONLY:
> +		tcphy_phy_init(tcphy);
> +		tcphy_usb3_init(tcphy);
> +		tcphy_dp_hpd(tcphy, 0);
> +		break;
> +	case MODE_DFP_DPONLY:
> +	case MODE_DFP_USB2DP:
> +		tcphy_phy_init(tcphy);
> +		tcphy_dp_init(tcphy);
> +		tcphy_dp_hpd(tcphy, 1);
> +		break;
> +	case MODE_DFP_USB3DP:
> +		tcphy_phy_init(tcphy);
> +		tcphy_usb3_init(tcphy);
> +		tcphy_dp_init(tcphy);
> +		tcphy_dp_hpd(tcphy, 1);
> +		break;
> +	}
> +}
> +
> +int tcphy_parse_reg(struct rockchip_typec_phy *tcphy, struct device *dev)
> +{
> +	struct tcphy_grf_reg *exregs = &tcphy->exregs;
> +	struct device_node *np = dev->of_node;
> +	u32 len = 0, array[3];
> +	int ret = 0;
> +
> +	PARSE_GRF_REG(con0);
> +	PARSE_GRF_REG(con1);
> +	PARSE_GRF_REG(con2);
> +	PARSE_GRF_REG(status0);
> +	PARSE_GRF_REG(status1);
> +	return ret;
> +}
> +
> +static int rockchip_typec_phy_probe(struct platform_device *pdev)
> +{
> +	struct device *dev = &pdev->dev;
> +	struct rockchip_typec_phy *tcphy;
> +	struct resource *res;
> +	struct phy_provider *phy_provider;
> +
> +	tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
> +	if (!tcphy)
> +		return -ENOMEM;
> +
> +	tcphy->dev = dev;
> +	platform_set_drvdata(pdev, tcphy);
> +
> +	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +	tcphy->base = devm_ioremap_resource(dev, res);
> +	if (IS_ERR(tcphy->base)) {
> +		dev_err(dev, "failed to remap phy regs\n");
> +		return PTR_ERR(tcphy->base);
> +	}
> +	tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node,
> +							"rockchip,grf");
> +	if (IS_ERR(tcphy->grf_regs)) {
> +		dev_err(dev, "%s: could not find grf dt node\n", __func__);
> +		return PTR_ERR(tcphy->grf_regs);
> +	}
> +
> +	tcphy->clk_core = of_clk_get_by_name(dev->of_node, "tcpdcore");
> +	if (IS_ERR(tcphy->clk_core)) {
> +		dev_err(dev, "%s: could not get uphy core clock\n", __func__);
> +		tcphy->clk_core = NULL;
> +	}
> +
> +	tcphy->clk_ref = of_clk_get_by_name(dev->of_node, "tcpdphy_ref");
> +	if (IS_ERR(tcphy->clk_core)) {
> +		dev_err(dev, "%s: could not get uphy ref clock\n", __func__);
> +		tcphy->clk_core = NULL;
> +	}
> +
> +	tcphy->phy_rst = devm_reset_control_get(dev, "tcphy_rst");
> +	if (IS_ERR(tcphy->phy_rst)) {
> +		dev_err(dev, "no phy_rst reset control found\n");
> +		return PTR_ERR(tcphy->phy_rst);
> +	}
> +
> +	tcphy->pipe_rst = devm_reset_control_get(dev, "tcphy_pipe_rst");
> +	if (IS_ERR(tcphy->pipe_rst)) {
> +		dev_err(dev, "no pipe_rst reset control found\n");
> +		return PTR_ERR(tcphy->pipe_rst);
> +	}
> +
> +	tcphy->uphy_rst = devm_reset_control_get(dev, "uphy_tcphy_rst");
> +	if (IS_ERR(tcphy->uphy_rst)) {
> +		dev_err(dev, "no uphy_rst reset control found\n");
> +		return PTR_ERR(tcphy->uphy_rst);
> +	}
> +
> +	tcphy_parse_reg(tcphy, dev);
> +	tcphy->mode = MODE_DISCONNECT;
> +
> +	tcphy->phy = devm_phy_create(dev, NULL, NULL);
> +
> +	phy_set_drvdata(tcphy->phy, tcphy);
> +
> +	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> +
> +	/* register notifier for PD event */
> +	ATOMIC_INIT_NOTIFIER_HEAD(&tcphy->notifier);
> +	tcphy->event_nb.notifier_call = tcphy_pd_event;
> +	INIT_DELAYED_WORK(&tcphy->event_wq, tcphy_event_wq);
> +	tcphy_register_notifier(tcphy->phy, &tcphy->event_nb);
> +
> +	return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static int rockchip_typec_phy_remove(struct platform_device *pdev)
> +{
> +	return 0;
> +}
> +
> +static const struct of_device_id rockchip_typec_phy_dt_ids[] = {
> +	{ .compatible = "rockchip,rk3399-typec-phy", },
> +	{}
> +};
> +
> +MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids);
> +
> +static struct platform_driver rockchip_typec_phy_driver = {
> +	.probe		= rockchip_typec_phy_probe,
> +	.remove		= rockchip_typec_phy_remove,
> +	.driver		= {
> +		.name	= "rockchip-typec-phy",
> +		.of_match_table = rockchip_typec_phy_dt_ids,
> +	},
> +};
> +
> +module_platform_driver(rockchip_typec_phy_driver);
> +
> +MODULE_AUTHOR("Kever Yang<kever.yang at rock-chips.com>");
> +MODULE_AUTHOR("Chris Zhong<zyw at rock-chips.com>");
> +MODULE_DESCRIPTION("Rockchip USB TYPE-C PHY driver");
> +MODULE_LICENSE("GPL v2");




From wxt at rock-chips.com  Fri May 27 01:23:24 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 27 May 2016 16:23:24 +0800
Subject: [PATCH v4 0/4] Thermal: Support for hardware-tracked trip points
Message-ID: <1464337408-7123-1-git-send-email-wxt@rock-chips.com>

The history patches come from Mikko and Sascha.
    http://thread.gmane.org/gmane.linux.power-management.general/59451

Now, I pick them up to continue upstream.
Nevermind!

This series history patches:
v3: https://lkml.org/lkml/2016/5/24/797
v2: https://lkml.org/lkml/2016/5/3/220
v1: https://lkml.org/lkml/2016/4/24/227

This series adds support for hardware trip points. It picks up earlier
work from Mikko Perttunen. Mikko implemented hardware trip points as part
of the device tree support. It was suggested back then to move the
functionality to the thermal core instead of putting more code into the
device tree support. This series does exactly that.

This series patches rebase the conflicts.
Note that the hardware-tracked trip points are very well tested currently.

Verified and tested on https://github.com/Caesar-github/rockchip/tree/wip/fixes-thermal-0525
That's based on linux-kernel 20160524.


Changes in v4:
- as the Javi comments, %s/implemnets/implements.

Changes in v3:
- as the Javi comments on https://patchwork.kernel.org/patch/9001311/.
- add the select if they set the option for devicetree.
- Add the peter's ACK.

Changes in v2:
- add the commit in patch[v2 2/5].
- Update the commit for patch[v2 4/5].

Caesar Wang (1):
  thermal: rockchip: add the set_trips function

Sascha Hauer (3):
  thermal: of: implement .set_trips for device tree thermal zones
  thermal: streamline get_trend callbacks
  thermal: bang-bang governor: act on lower trip boundary

 drivers/thermal/gov_bang_bang.c                    |  2 +-
 drivers/thermal/of-thermal.c                       | 30 +++++++++++------
 drivers/thermal/rockchip_thermal.c                 | 39 ++++++++++++++++++++++
 drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 25 +++++---------
 include/linux/thermal.h                            |  6 +++-
 5 files changed, 73 insertions(+), 29 deletions(-)

-- 
1.9.1



From wxt at rock-chips.com  Fri May 27 01:23:25 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 27 May 2016 16:23:25 +0800
Subject: [PATCH v4 1/4] thermal: of: implement .set_trips for device tree
 thermal zones
In-Reply-To: <1464337408-7123-1-git-send-email-wxt@rock-chips.com>
References: <1464337408-7123-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464337408-7123-2-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

This patch implements .set_trips for device tree thermal zones.
As the hardware-tracked trip points is supported by thermal core patch[0].

patch[0]
"thermal: Add support for hardware-tracked trip points".

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Reviewed-by: Javi Merino <javi.merino at arm.com>

---

Changes in v4:
- as the Javi comments, %s/implemnets/implements.

Changes in v3:
- as the Javi comments on https://patchwork.kernel.org/patch/9001311/.
- add the select if they set the option for devicetree.

Changes in v2:
- add the commit in patch[v2 2/5].

 drivers/thermal/of-thermal.c | 19 +++++++++++++++++++
 include/linux/thermal.h      |  4 ++++
 2 files changed, 23 insertions(+)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index b8e509c..2d2a06f 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -101,6 +101,17 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
 	return data->ops->get_temp(data->sensor_data, temp);
 }
 
+static int of_thermal_set_trips(struct thermal_zone_device *tz,
+				int low, int high)
+{
+	struct __thermal_zone *data = tz->devdata;
+
+	if (!data->ops || !data->ops->set_trips)
+		return -EINVAL;
+
+	return data->ops->set_trips(data->sensor_data, low, high);
+}
+
 /**
  * of_thermal_get_ntrips - function to export number of available trip
  *			   points.
@@ -427,6 +438,14 @@ thermal_zone_of_add_sensor(struct device_node *zone,
 
 	tzd->ops->get_temp = of_thermal_get_temp;
 	tzd->ops->get_trend = of_thermal_get_trend;
+
+	/*
+	 * The thermal zone core will calculate the window if they have set the
+	 * optional set_trips pointer.
+	 */
+	if (ops->set_trips)
+		tzd->ops->set_trips = of_thermal_set_trips;
+
 	tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
 	mutex_unlock(&tzd->lock);
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 635c4003..f68da05 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -340,12 +340,16 @@ struct thermal_genl_event {
  *
  * Optional:
  * @get_trend: a pointer to a function that reads the sensor temperature trend.
+ * @set_trips: a pointer to a function that sets a temperature window. When
+ *	       this window is left the driver must inform the thermal core via
+ *	       thermal_zone_device_update.
  * @set_emul_temp: a pointer to a function that sets sensor emulated
  *		   temperature.
  */
 struct thermal_zone_of_device_ops {
 	int (*get_temp)(void *, int *);
 	int (*get_trend)(void *, long *);
+	int (*set_trips)(void *, int, int);
 	int (*set_emul_temp)(void *, int);
 	int (*set_trip_temp)(void *, int, int);
 };
-- 
1.9.1



From wxt at rock-chips.com  Fri May 27 01:23:26 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 27 May 2016 16:23:26 +0800
Subject: [PATCH v4 2/4] thermal: streamline get_trend callbacks
In-Reply-To: <1464337408-7123-1-git-send-email-wxt@rock-chips.com>
References: <1464337408-7123-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464337408-7123-3-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

The .get_trend callback in struct thermal_zone_device_ops has
the prototype:
        int (*get_trend) (struct thermal_zone_device *, int,
                          enum thermal_trend *);
whereas the .get_trend callback in struct thermal_zone_of_device_ops
has:
        int (*get_trend)(void *, long *);

Streamline both prototypes and add the trip argument to the OF callback
aswell and use enum thermal_trend * instead of an integer pointer.

While the OF prototype may be the better one, this should be decided at
framework level and not on OF level.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/thermal/of-thermal.c                       | 11 +---------
 drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 25 +++++++---------------
 include/linux/thermal.h                            |  2 +-
 3 files changed, 10 insertions(+), 28 deletions(-)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 2d2a06f..ba72c35 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -202,24 +202,15 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
 				enum thermal_trend *trend)
 {
 	struct __thermal_zone *data = tz->devdata;
-	long dev_trend;
 	int r;
 
 	if (!data->ops->get_trend)
 		return -EINVAL;
 
-	r = data->ops->get_trend(data->sensor_data, &dev_trend);
+	r = data->ops->get_trend(data->sensor_data, trip, trend);
 	if (r)
 		return r;
 
-	/* TODO: These intervals might have some thresholds, but in core code */
-	if (dev_trend > 0)
-		*trend = THERMAL_TREND_RAISING;
-	else if (dev_trend < 0)
-		*trend = THERMAL_TREND_DROPPING;
-	else
-		*trend = THERMAL_TREND_STABLE;
-
 	return 0;
 }
 
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
index 15c0a9a..4a6757c 100644
--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
@@ -239,7 +239,7 @@ static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int __ti_thermal_get_trend(void *p, long *trend)
+static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend)
 {
 	struct ti_thermal_data *data = p;
 	struct ti_bandgap *bgp;
@@ -252,22 +252,6 @@ static int __ti_thermal_get_trend(void *p, long *trend)
 	if (ret)
 		return ret;
 
-	*trend = tr;
-
-	return 0;
-}
-
-/* Get the temperature trend callback functions for thermal zone */
-static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
-				int trip, enum thermal_trend *trend)
-{
-	int ret;
-	long tr;
-
-	ret = __ti_thermal_get_trend(thermal->devdata, &tr);
-	if (ret)
-		return ret;
-
 	if (tr > 0)
 		*trend = THERMAL_TREND_RAISING;
 	else if (tr < 0)
@@ -278,6 +262,13 @@ static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
 	return 0;
 }
 
+/* Get the temperature trend callback functions for thermal zone */
+static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
+				int trip, enum thermal_trend *trend)
+{
+	return __ti_thermal_get_trend(thermal->devdata, trip, trend);
+}
+
 /* Get critical temperature callback functions for thermal zone */
 static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
 				    int *temp)
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index f68da05..669093c 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -348,7 +348,7 @@ struct thermal_genl_event {
  */
 struct thermal_zone_of_device_ops {
 	int (*get_temp)(void *, int *);
-	int (*get_trend)(void *, long *);
+	int (*get_trend)(void *, int, enum thermal_trend *);
 	int (*set_trips)(void *, int, int);
 	int (*set_emul_temp)(void *, int);
 	int (*set_trip_temp)(void *, int, int);
-- 
1.9.1



From wxt at rock-chips.com  Fri May 27 01:23:27 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 27 May 2016 16:23:27 +0800
Subject: [PATCH v4 3/4] thermal: bang-bang governor: act on lower trip boundary
In-Reply-To: <1464337408-7123-1-git-send-email-wxt@rock-chips.com>
References: <1464337408-7123-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464337408-7123-4-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

With interrupt driven thermal zones we pass the lower and upper
temperature on which shall be acted, so in the governor we have to act on
the exact lower temperature to be consistent. Otherwise an interrupt maybe
generated on the exact lower temperature, but the bang bang governor does
not react since The polling driven zones have to be one step cooler before
the governor reacts.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org
Acked-by: Peter Feuerer <peter at piie.net>

---

Changes in v4: None
Changes in v3:
- Add the peter's ACK.

Changes in v2:
- Update the commit for patch[v2 4/5].

 drivers/thermal/gov_bang_bang.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
index 70836c5..9d1dfea 100644
--- a/drivers/thermal/gov_bang_bang.c
+++ b/drivers/thermal/gov_bang_bang.c
@@ -59,7 +59,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
 		if (instance->target == 0 && tz->temperature >= trip_temp)
 			instance->target = 1;
 		else if (instance->target == 1 &&
-				tz->temperature < trip_temp - trip_hyst)
+				tz->temperature <= trip_temp - trip_hyst)
 			instance->target = 0;
 
 		dev_dbg(&instance->cdev->device, "target=%d\n",
-- 
1.9.1



From wxt at rock-chips.com  Fri May 27 01:23:28 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 27 May 2016 16:23:28 +0800
Subject: [PATCH v4 4/4] thermal: rockchip: add the set_trips function
In-Reply-To: <1464337408-7123-1-git-send-email-wxt@rock-chips.com>
References: <1464337408-7123-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464337408-7123-5-git-send-email-wxt@rock-chips.com>

Whenever the current temperature is updated, the trip points immediately
below and above the current temperature are found. A sensor driver
callback `set_trips' is then called with the temperatures.
Lastly, The sensor will trigger the hardware high temperature interrupts
to increase the sampleing rate and throttle frequency to limit the
temperature rising When performing passive cooling.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org

---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/thermal/rockchip_thermal.c | 39 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index 86a1ab0..39e2eec 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -96,6 +96,7 @@ struct chip_tsadc_table {
  * @initialize: SoC special initialize tsadc controller method
  * @irq_ack: clear the interrupt
  * @get_temp: get the temperature
+ * @set_alarm_temp: set the high temperature interrupt
  * @set_tshut_temp: set the hardware-controlled shutdown temperature
  * @set_tshut_mode: set the hardware-controlled shutdown mode
  * @table: the chip-specific conversion table
@@ -119,6 +120,8 @@ struct rockchip_tsadc_chip {
 	/* Per-sensor methods */
 	int (*get_temp)(struct chip_tsadc_table table,
 			int chn, void __iomem *reg, int *temp);
+	void (*set_alarm_temp)(struct chip_tsadc_table table,
+			       int chn, void __iomem *reg, int temp);
 	void (*set_tshut_temp)(struct chip_tsadc_table table,
 			       int chn, void __iomem *reg, int temp);
 	void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
@@ -183,6 +186,7 @@ struct rockchip_thermal_data {
 #define TSADCV2_INT_EN				0x08
 #define TSADCV2_INT_PD				0x0c
 #define TSADCV2_DATA(chn)			(0x20 + (chn) * 0x04)
+#define TSADCV2_COMP_INT(chn)		        (0x30 + (chn) * 0x04)
 #define TSADCV2_COMP_SHUT(chn)		        (0x40 + (chn) * 0x04)
 #define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
 #define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
@@ -628,6 +632,20 @@ static int rk_tsadcv2_get_temp(struct chip_tsadc_table table,
 	return rk_tsadcv2_code_to_temp(table, val, temp);
 }
 
+static void rk_tsadcv2_alarm_temp(struct chip_tsadc_table table,
+				  int chn, void __iomem *regs, int temp)
+{
+	u32 alarm_value, int_en;
+
+	alarm_value = rk_tsadcv2_temp_to_code(table, temp);
+	writel_relaxed(alarm_value & table.data_mask,
+		       regs + TSADCV2_COMP_INT(chn));
+
+	int_en = readl_relaxed(regs + TSADCV2_INT_EN);
+	int_en |= TSADCV2_INT_SRC_EN(chn);
+	writel_relaxed(int_en, regs + TSADCV2_INT_EN);
+}
+
 static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table,
 				  int chn, void __iomem *regs, int temp)
 {
@@ -670,6 +688,7 @@ static const struct rockchip_tsadc_chip rk3228_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -694,6 +713,7 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
 	.irq_ack = rk_tsadcv2_irq_ack,
 	.control = rk_tsadcv2_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -718,6 +738,7 @@ static const struct rockchip_tsadc_chip rk3366_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -742,6 +763,7 @@ static const struct rockchip_tsadc_chip rk3368_tsadc_data = {
 	.irq_ack = rk_tsadcv2_irq_ack,
 	.control = rk_tsadcv2_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -766,6 +788,7 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -826,6 +849,21 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
+static int rockchip_thermal_set_trips(void *_sensor, int low, int high)
+{
+	struct rockchip_thermal_sensor *sensor = _sensor;
+	struct rockchip_thermal_data *thermal = sensor->thermal;
+	const struct rockchip_tsadc_chip *tsadc = thermal->chip;
+
+	dev_dbg(&thermal->pdev->dev, "%s: sensor %d: low: %d, high %d\n",
+		__func__, sensor->id, low, high);
+
+	tsadc->set_alarm_temp(tsadc->table,
+			      sensor->id, thermal->regs, high);
+
+	return 0;
+}
+
 static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
 {
 	struct rockchip_thermal_sensor *sensor = _sensor;
@@ -843,6 +881,7 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
 
 static const struct thermal_zone_of_device_ops rockchip_of_thermal_ops = {
 	.get_temp = rockchip_thermal_get_temp,
+	.set_trips = rockchip_thermal_set_trips,
 };
 
 static int rockchip_configure_from_dt(struct device *dev,
-- 
1.9.1



From heiko at sntech.de  Fri May 27 01:29:57 2016
From: heiko at sntech.de (Heiko Stuebner)
Date: Fri, 27 May 2016 10:29:57 +0200
Subject: [PATCH 2/6] Documentation: bindings: add dt doc for Rockchip USB
 Type-C PHY
In-Reply-To: <1464328939-8073-3-git-send-email-zyw@rock-chips.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
 <1464328939-8073-3-git-send-email-zyw@rock-chips.com>
Message-ID: <2812026.ptEv4ktvbn@phil>

Hi Chris,

Am Freitag, 27. Mai 2016, 14:02:15 schrieb Chris Zhong:
> This patch adds a binding that describes the Rockchip USB Type-C PHY
> for rk3399.
> 
> Signed-off-by: Chris Zhong <zyw at rock-chips.com>
> ---
> 
>  .../devicetree/bindings/phy/phy-rockchip-typec.txt | 55
> ++++++++++++++++++++++ 1 file changed, 55 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
> 
> diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
> b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file
> mode 100644
> index 0000000..402f667
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
> @@ -0,0 +1,55 @@
> +ROCKCHIP type-c PHY
> +
> +Required properties:
> + - compatible: should be "rockchip,rk3399-typec-phy"
> + - reg : Address and length of the usb phy control register set
> + - rockchip,grf : phandle to the syscon managing the "general
> +   register files"
> + - clocks : phandle + clock specifier for the phy clocks
> + - clock-names: string, clock name, must be "tcpdcore", "tcpdphy_ref";
> + - resets : a list of phandle + reset specifier pairs
> + - reset-names : string reset name, must be:
> +		 "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst"
> + - #phy-cells: Must be 0.  See ./phy-bindings.txt for details.
> + - rockchip,usb3phy*: phy registers embed in grf
> +
> +Example:
> +	tcphy0: phy at ff7c0000 {
> +		compatible = "rockchip,rk3399-typec-phy";
> +		reg = <0x0 0xff7c0000 0x0 0x40000>;
> +		#phy-cells = <0>;
> +		rockchip,grf = <&grf>;
> +		clocks = <&cru SCLK_UPHY0_TCPDCORE>,
> +			 <&cru SCLK_UPHY0_TCPDPHY_REF>;
> +		clock-names = "tcpdcore", "tcpdphy_ref";
> +		resets = <&cru SRST_UPHY0>,
> +			 <&cru SRST_UPHY0_PIPE_L00>,
> +			 <&cru SRST_P_UPHY0_TCPHY>;
> +		reset-names = "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst";
> +		rockchip,usb3phy_con0 = <0x0e580 0 16>;
> +		rockchip,usb3phy_con1 = <0x0e584 0 16>;
> +		rockchip,usb3phy_con2 = <0x0e588 0 16>;
> +		rockchip,usb3phy_status0 = <0x0e5c0 0 13>;
> +		rockchip,usb3phy_status1 = <0x0e5c4 0 12>;

please embedded this register data in the driver instead (not in the 
devicetree), matched against the compatible value.
See Frank's usb2phy driver for reference if needed.


Thanks
Heiko



From wxt at rock-chips.com  Fri May 27 01:36:44 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 27 May 2016 16:36:44 +0800
Subject: [RESEND PATCH v4 1/5] thermal: Add support for hardware-tracked trip
 points
In-Reply-To: <1464338208-8105-1-git-send-email-wxt@rock-chips.com>
References: <1464338208-8105-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464338208-8105-2-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

This adds support for hardware-tracked trip points to the device tree
thermal sensor framework.

The framework supports an arbitrary number of trip points. Whenever
the current temperature is updated, the trip points immediately
below and above the current temperature are found. A .set_trips
callback is then called with the temperatures. If there is no trip
point above or below the current temperature, the passed trip
temperature will be -INT_MAX or INT_MAX respectively. In this callback,
the driver should program the hardware such that it is notified
when either of these trip points are triggered. When a trip point
is triggered, the driver should call `thermal_zone_device_update'
for the respective thermal zone. This will cause the trip points
to be updated again.

If .set_trips is not implemented, the framework behaves as before.

This patch is based on an earlier version from Mikko Perttunen
<mikko.perttunen at kapsi.fi>

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org

---

Changes in v4:
- Missing the lock added in v3.

Changes in v3:
- as Javi comments on https://patchwork.kernel.org/patch/9001281/.
- add the lock for preventing the called from multi placce
- add the note for pre_low/high_trip.

Changes in v2:
- update the sysfs-api.txt for set_trips.

 Documentation/thermal/sysfs-api.txt |  7 +++++
 drivers/thermal/thermal_core.c      | 56 +++++++++++++++++++++++++++++++++++++
 include/linux/thermal.h             |  7 +++++
 3 files changed, 70 insertions(+)

diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt
index efc3f3d..75d8838 100644
--- a/Documentation/thermal/sysfs-api.txt
+++ b/Documentation/thermal/sysfs-api.txt
@@ -49,6 +49,9 @@ temperature) and throttle appropriate devices.
 	.bind: bind the thermal zone device with a thermal cooling device.
 	.unbind: unbind the thermal zone device with a thermal cooling device.
 	.get_temp: get the current temperature of the thermal zone.
+	.set_trips: set the trip points window. Whenever the current temperature
+		    is updated, the trip points immediately below and above the
+		    current temperature are found.
 	.get_mode: get the current mode (enabled/disabled) of the thermal zone.
 	    - "enabled" means the kernel thermal management is enabled.
 	    - "disabled" will prevent kernel thermal driver action upon trip points
@@ -95,6 +98,10 @@ temperature) and throttle appropriate devices.
 			get_temp:	a pointer to a function that reads the
 					sensor temperature. This is mandatory
 					callback provided by sensor driver.
+			set_trips:      a pointer to a function that sets a
+					temperature window. When this window is
+					left the driver must inform the thermal
+					core via thermal_zone_device_update.
 			get_trend: 	a pointer to a function that reads the
 					sensor temperature trend.
 			set_emul_temp:	a pointer to a function that sets
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 5133cd1..0591438 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -520,6 +520,55 @@ exit:
 }
 EXPORT_SYMBOL_GPL(thermal_zone_get_temp);
 
+static void thermal_zone_set_trips(struct thermal_zone_device *tz)
+{
+	int low = -INT_MAX;
+	int high = INT_MAX;
+	int trip_temp, hysteresis;
+	int temp = tz->temperature;
+	int i, ret;
+
+	if (!tz->ops->set_trips)
+		return;
+
+	for (i = 0; i < tz->trips; i++) {
+		int trip_low;
+
+		tz->ops->get_trip_temp(tz, i, &trip_temp);
+		tz->ops->get_trip_hyst(tz, i, &hysteresis);
+
+		trip_low = trip_temp - hysteresis;
+
+		if (trip_low < temp && trip_low > low)
+			low = trip_low;
+
+		if (trip_temp > temp && trip_temp < high)
+			high = trip_temp;
+	}
+
+	/* No need to change trip points */
+	if (tz->prev_low_trip == low && tz->prev_high_trip == high)
+		return;
+
+	mutex_lock(&tz->lock);
+
+	tz->prev_low_trip = low;
+	tz->prev_high_trip = high;
+
+	dev_dbg(&tz->device, "new temperature boundaries: %d < x < %d\n",
+			low, high);
+
+	/*
+	 * Set a temperature window. When this window is left the driver
+	 * must inform the thermal core via thermal_zone_device_update.
+	 */
+	ret = tz->ops->set_trips(tz, low, high);
+	if (ret)
+		dev_err(&tz->device, "Failed to set trips: %d\n", ret);
+
+	mutex_unlock(&tz->lock);
+}
+
 static void update_temperature(struct thermal_zone_device *tz)
 {
 	int temp, ret;
@@ -569,6 +618,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz)
 
 	update_temperature(tz);
 
+	thermal_zone_set_trips(tz);
+
 	for (count = 0; count < tz->trips; count++)
 		handle_thermal_trip(tz, count);
 }
@@ -754,6 +805,9 @@ trip_point_hyst_store(struct device *dev, struct device_attribute *attr,
 	 */
 	ret = tz->ops->set_trip_hyst(tz, trip, temperature);
 
+	if (!ret)
+		thermal_zone_set_trips(tz);
+
 	return ret ? ret : count;
 }
 
@@ -1843,6 +1897,8 @@ struct thermal_zone_device *thermal_zone_device_register(const char *type,
 	tz->trips = trips;
 	tz->passive_delay = passive_delay;
 	tz->polling_delay = polling_delay;
+	tz->prev_low_trip = INT_MAX;
+	tz->prev_high_trip = -INT_MAX;
 	/* A new thermal zone needs to be updated anyway. */
 	atomic_set(&tz->need_update, 1);
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index e45abe7..635c4003 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -98,6 +98,7 @@ struct thermal_zone_device_ops {
 	int (*unbind) (struct thermal_zone_device *,
 		       struct thermal_cooling_device *);
 	int (*get_temp) (struct thermal_zone_device *, int *);
+	int (*set_trips) (struct thermal_zone_device *, int, int);
 	int (*get_mode) (struct thermal_zone_device *,
 			 enum thermal_device_mode *);
 	int (*set_mode) (struct thermal_zone_device *,
@@ -168,6 +169,10 @@ struct thermal_attr {
  * @last_temperature:	previous temperature read
  * @emul_temperature:	emulated temperature when using CONFIG_THERMAL_EMULATION
  * @passive:		1 if you've crossed a passive trip point, 0 otherwise.
+ * @prev_low_trip:	the low current temperature if you've crossed a passive
+			trip point.
+ * @prev_high_trip:	the above current temperature if you've crossed a
+			passive trip point.
  * @forced_passive:	If > 0, temperature at which to switch on all ACPI
  *			processor cooling devices.  Currently only used by the
  *			step-wise governor.
@@ -199,6 +204,8 @@ struct thermal_zone_device {
 	int last_temperature;
 	int emul_temperature;
 	int passive;
+	int prev_low_trip;
+	int prev_high_trip;
 	unsigned int forced_passive;
 	atomic_t need_update;
 	struct thermal_zone_device_ops *ops;
-- 
1.9.1



From wxt at rock-chips.com  Fri May 27 01:36:45 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 27 May 2016 16:36:45 +0800
Subject: [RESEND PATCH v4 2/5] thermal: of: implement .set_trips for device
 tree thermal zones
In-Reply-To: <1464338208-8105-1-git-send-email-wxt@rock-chips.com>
References: <1464338208-8105-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464338208-8105-3-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

This patch implements .set_trips for device tree thermal zones.
As the hardware-tracked trip points is supported by thermal core patch[0].

patch[0]
"thermal: Add support for hardware-tracked trip points".

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Reviewed-by: Javi Merino <javi.merino at arm.com>

---

Changes in v4:
- as the Javi comments, %s/implemnets/implements.

Changes in v3:
- as the Javi comments on https://patchwork.kernel.org/patch/9001311/.
- add the select if they set the option for devicetree.

Changes in v2:
- add the commit in patch[v2 2/5].

 drivers/thermal/of-thermal.c | 19 +++++++++++++++++++
 include/linux/thermal.h      |  4 ++++
 2 files changed, 23 insertions(+)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index b8e509c..2d2a06f 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -101,6 +101,17 @@ static int of_thermal_get_temp(struct thermal_zone_device *tz,
 	return data->ops->get_temp(data->sensor_data, temp);
 }
 
+static int of_thermal_set_trips(struct thermal_zone_device *tz,
+				int low, int high)
+{
+	struct __thermal_zone *data = tz->devdata;
+
+	if (!data->ops || !data->ops->set_trips)
+		return -EINVAL;
+
+	return data->ops->set_trips(data->sensor_data, low, high);
+}
+
 /**
  * of_thermal_get_ntrips - function to export number of available trip
  *			   points.
@@ -427,6 +438,14 @@ thermal_zone_of_add_sensor(struct device_node *zone,
 
 	tzd->ops->get_temp = of_thermal_get_temp;
 	tzd->ops->get_trend = of_thermal_get_trend;
+
+	/*
+	 * The thermal zone core will calculate the window if they have set the
+	 * optional set_trips pointer.
+	 */
+	if (ops->set_trips)
+		tzd->ops->set_trips = of_thermal_set_trips;
+
 	tzd->ops->set_emul_temp = of_thermal_set_emul_temp;
 	mutex_unlock(&tzd->lock);
 
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 635c4003..f68da05 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -340,12 +340,16 @@ struct thermal_genl_event {
  *
  * Optional:
  * @get_trend: a pointer to a function that reads the sensor temperature trend.
+ * @set_trips: a pointer to a function that sets a temperature window. When
+ *	       this window is left the driver must inform the thermal core via
+ *	       thermal_zone_device_update.
  * @set_emul_temp: a pointer to a function that sets sensor emulated
  *		   temperature.
  */
 struct thermal_zone_of_device_ops {
 	int (*get_temp)(void *, int *);
 	int (*get_trend)(void *, long *);
+	int (*set_trips)(void *, int, int);
 	int (*set_emul_temp)(void *, int);
 	int (*set_trip_temp)(void *, int, int);
 };
-- 
1.9.1



From wxt at rock-chips.com  Fri May 27 01:36:46 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 27 May 2016 16:36:46 +0800
Subject: [RESEND PATCH v4 3/5] thermal: streamline get_trend callbacks
In-Reply-To: <1464338208-8105-1-git-send-email-wxt@rock-chips.com>
References: <1464338208-8105-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464338208-8105-4-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

The .get_trend callback in struct thermal_zone_device_ops has
the prototype:
        int (*get_trend) (struct thermal_zone_device *, int,
                          enum thermal_trend *);
whereas the .get_trend callback in struct thermal_zone_of_device_ops
has:
        int (*get_trend)(void *, long *);

Streamline both prototypes and add the trip argument to the OF callback
aswell and use enum thermal_trend * instead of an integer pointer.

While the OF prototype may be the better one, this should be decided at
framework level and not on OF level.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org
---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/thermal/of-thermal.c                       | 11 +---------
 drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 25 +++++++---------------
 include/linux/thermal.h                            |  2 +-
 3 files changed, 10 insertions(+), 28 deletions(-)

diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 2d2a06f..ba72c35 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -202,24 +202,15 @@ static int of_thermal_get_trend(struct thermal_zone_device *tz, int trip,
 				enum thermal_trend *trend)
 {
 	struct __thermal_zone *data = tz->devdata;
-	long dev_trend;
 	int r;
 
 	if (!data->ops->get_trend)
 		return -EINVAL;
 
-	r = data->ops->get_trend(data->sensor_data, &dev_trend);
+	r = data->ops->get_trend(data->sensor_data, trip, trend);
 	if (r)
 		return r;
 
-	/* TODO: These intervals might have some thresholds, but in core code */
-	if (dev_trend > 0)
-		*trend = THERMAL_TREND_RAISING;
-	else if (dev_trend < 0)
-		*trend = THERMAL_TREND_DROPPING;
-	else
-		*trend = THERMAL_TREND_STABLE;
-
 	return 0;
 }
 
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
index 15c0a9a..4a6757c 100644
--- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
+++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c
@@ -239,7 +239,7 @@ static int ti_thermal_get_trip_temp(struct thermal_zone_device *thermal,
 	return 0;
 }
 
-static int __ti_thermal_get_trend(void *p, long *trend)
+static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend)
 {
 	struct ti_thermal_data *data = p;
 	struct ti_bandgap *bgp;
@@ -252,22 +252,6 @@ static int __ti_thermal_get_trend(void *p, long *trend)
 	if (ret)
 		return ret;
 
-	*trend = tr;
-
-	return 0;
-}
-
-/* Get the temperature trend callback functions for thermal zone */
-static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
-				int trip, enum thermal_trend *trend)
-{
-	int ret;
-	long tr;
-
-	ret = __ti_thermal_get_trend(thermal->devdata, &tr);
-	if (ret)
-		return ret;
-
 	if (tr > 0)
 		*trend = THERMAL_TREND_RAISING;
 	else if (tr < 0)
@@ -278,6 +262,13 @@ static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
 	return 0;
 }
 
+/* Get the temperature trend callback functions for thermal zone */
+static int ti_thermal_get_trend(struct thermal_zone_device *thermal,
+				int trip, enum thermal_trend *trend)
+{
+	return __ti_thermal_get_trend(thermal->devdata, trip, trend);
+}
+
 /* Get critical temperature callback functions for thermal zone */
 static int ti_thermal_get_crit_temp(struct thermal_zone_device *thermal,
 				    int *temp)
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index f68da05..669093c 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -348,7 +348,7 @@ struct thermal_genl_event {
  */
 struct thermal_zone_of_device_ops {
 	int (*get_temp)(void *, int *);
-	int (*get_trend)(void *, long *);
+	int (*get_trend)(void *, int, enum thermal_trend *);
 	int (*set_trips)(void *, int, int);
 	int (*set_emul_temp)(void *, int);
 	int (*set_trip_temp)(void *, int, int);
-- 
1.9.1



From wxt at rock-chips.com  Fri May 27 01:36:47 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 27 May 2016 16:36:47 +0800
Subject: [RESEND PATCH v4 4/5] thermal: bang-bang governor: act on lower trip
 boundary
In-Reply-To: <1464338208-8105-1-git-send-email-wxt@rock-chips.com>
References: <1464338208-8105-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464338208-8105-5-git-send-email-wxt@rock-chips.com>

From: Sascha Hauer <s.hauer at pengutronix.de>

With interrupt driven thermal zones we pass the lower and upper
temperature on which shall be acted, so in the governor we have to act on
the exact lower temperature to be consistent. Otherwise an interrupt maybe
generated on the exact lower temperature, but the bang bang governor does
not react since The polling driven zones have to be one step cooler before
the governor reacts.

Signed-off-by: Sascha Hauer <s.hauer at pengutronix.de>
Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org
Acked-by: Peter Feuerer <peter at piie.net>

---

Changes in v4: None
Changes in v3:
- Add the peter's ACK.

Changes in v2:
- Update the commit for patch[v2 4/5].

 drivers/thermal/gov_bang_bang.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
index 70836c5..9d1dfea 100644
--- a/drivers/thermal/gov_bang_bang.c
+++ b/drivers/thermal/gov_bang_bang.c
@@ -59,7 +59,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
 		if (instance->target == 0 && tz->temperature >= trip_temp)
 			instance->target = 1;
 		else if (instance->target == 1 &&
-				tz->temperature < trip_temp - trip_hyst)
+				tz->temperature <= trip_temp - trip_hyst)
 			instance->target = 0;
 
 		dev_dbg(&instance->cdev->device, "target=%d\n",
-- 
1.9.1



From wxt at rock-chips.com  Fri May 27 01:36:48 2016
From: wxt at rock-chips.com (Caesar Wang)
Date: Fri, 27 May 2016 16:36:48 +0800
Subject: [RESEND PATCH v4 5/5] thermal: rockchip: add the set_trips function
In-Reply-To: <1464338208-8105-1-git-send-email-wxt@rock-chips.com>
References: <1464338208-8105-1-git-send-email-wxt@rock-chips.com>
Message-ID: <1464338208-8105-6-git-send-email-wxt@rock-chips.com>

Whenever the current temperature is updated, the trip points immediately
below and above the current temperature are found. A sensor driver
callback `set_trips' is then called with the temperatures.
Lastly, The sensor will trigger the hardware high temperature interrupts
to increase the sampleing rate and throttle frequency to limit the
temperature rising When performing passive cooling.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Cc: Zhang Rui <rui.zhang at intel.com>
Cc: Eduardo Valentin <edubezval at gmail.com>
Cc: linux-pm at vger.kernel.org

---

Changes in v4: None
Changes in v3: None
Changes in v2: None

 drivers/thermal/rockchip_thermal.c | 39 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 39 insertions(+)

diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c
index 86a1ab0..39e2eec 100644
--- a/drivers/thermal/rockchip_thermal.c
+++ b/drivers/thermal/rockchip_thermal.c
@@ -96,6 +96,7 @@ struct chip_tsadc_table {
  * @initialize: SoC special initialize tsadc controller method
  * @irq_ack: clear the interrupt
  * @get_temp: get the temperature
+ * @set_alarm_temp: set the high temperature interrupt
  * @set_tshut_temp: set the hardware-controlled shutdown temperature
  * @set_tshut_mode: set the hardware-controlled shutdown mode
  * @table: the chip-specific conversion table
@@ -119,6 +120,8 @@ struct rockchip_tsadc_chip {
 	/* Per-sensor methods */
 	int (*get_temp)(struct chip_tsadc_table table,
 			int chn, void __iomem *reg, int *temp);
+	void (*set_alarm_temp)(struct chip_tsadc_table table,
+			       int chn, void __iomem *reg, int temp);
 	void (*set_tshut_temp)(struct chip_tsadc_table table,
 			       int chn, void __iomem *reg, int temp);
 	void (*set_tshut_mode)(int chn, void __iomem *reg, enum tshut_mode m);
@@ -183,6 +186,7 @@ struct rockchip_thermal_data {
 #define TSADCV2_INT_EN				0x08
 #define TSADCV2_INT_PD				0x0c
 #define TSADCV2_DATA(chn)			(0x20 + (chn) * 0x04)
+#define TSADCV2_COMP_INT(chn)		        (0x30 + (chn) * 0x04)
 #define TSADCV2_COMP_SHUT(chn)		        (0x40 + (chn) * 0x04)
 #define TSADCV2_HIGHT_INT_DEBOUNCE		0x60
 #define TSADCV2_HIGHT_TSHUT_DEBOUNCE		0x64
@@ -628,6 +632,20 @@ static int rk_tsadcv2_get_temp(struct chip_tsadc_table table,
 	return rk_tsadcv2_code_to_temp(table, val, temp);
 }
 
+static void rk_tsadcv2_alarm_temp(struct chip_tsadc_table table,
+				  int chn, void __iomem *regs, int temp)
+{
+	u32 alarm_value, int_en;
+
+	alarm_value = rk_tsadcv2_temp_to_code(table, temp);
+	writel_relaxed(alarm_value & table.data_mask,
+		       regs + TSADCV2_COMP_INT(chn));
+
+	int_en = readl_relaxed(regs + TSADCV2_INT_EN);
+	int_en |= TSADCV2_INT_SRC_EN(chn);
+	writel_relaxed(int_en, regs + TSADCV2_INT_EN);
+}
+
 static void rk_tsadcv2_tshut_temp(struct chip_tsadc_table table,
 				  int chn, void __iomem *regs, int temp)
 {
@@ -670,6 +688,7 @@ static const struct rockchip_tsadc_chip rk3228_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -694,6 +713,7 @@ static const struct rockchip_tsadc_chip rk3288_tsadc_data = {
 	.irq_ack = rk_tsadcv2_irq_ack,
 	.control = rk_tsadcv2_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -718,6 +738,7 @@ static const struct rockchip_tsadc_chip rk3366_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -742,6 +763,7 @@ static const struct rockchip_tsadc_chip rk3368_tsadc_data = {
 	.irq_ack = rk_tsadcv2_irq_ack,
 	.control = rk_tsadcv2_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -766,6 +788,7 @@ static const struct rockchip_tsadc_chip rk3399_tsadc_data = {
 	.irq_ack = rk_tsadcv3_irq_ack,
 	.control = rk_tsadcv3_control,
 	.get_temp = rk_tsadcv2_get_temp,
+	.set_alarm_temp = rk_tsadcv2_alarm_temp,
 	.set_tshut_temp = rk_tsadcv2_tshut_temp,
 	.set_tshut_mode = rk_tsadcv2_tshut_mode,
 
@@ -826,6 +849,21 @@ static irqreturn_t rockchip_thermal_alarm_irq_thread(int irq, void *dev)
 	return IRQ_HANDLED;
 }
 
+static int rockchip_thermal_set_trips(void *_sensor, int low, int high)
+{
+	struct rockchip_thermal_sensor *sensor = _sensor;
+	struct rockchip_thermal_data *thermal = sensor->thermal;
+	const struct rockchip_tsadc_chip *tsadc = thermal->chip;
+
+	dev_dbg(&thermal->pdev->dev, "%s: sensor %d: low: %d, high %d\n",
+		__func__, sensor->id, low, high);
+
+	tsadc->set_alarm_temp(tsadc->table,
+			      sensor->id, thermal->regs, high);
+
+	return 0;
+}
+
 static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
 {
 	struct rockchip_thermal_sensor *sensor = _sensor;
@@ -843,6 +881,7 @@ static int rockchip_thermal_get_temp(void *_sensor, int *out_temp)
 
 static const struct thermal_zone_of_device_ops rockchip_of_thermal_ops = {
 	.get_temp = rockchip_thermal_get_temp,
+	.set_trips = rockchip_thermal_set_trips,
 };
 
 static int rockchip_configure_from_dt(struct device *dev,
-- 
1.9.1



From caesar.upstream at gmail.com  Fri May 27 01:41:59 2016
From: caesar.upstream at gmail.com (Caesar Wang)
Date: Fri, 27 May 2016 16:41:59 +0800
Subject: [PATCH v4 0/4] Thermal: Support for hardware-tracked trip points
In-Reply-To: <1464337408-7123-1-git-send-email-wxt@rock-chips.com>
References: <1464337408-7123-1-git-send-email-wxt@rock-chips.com>
Message-ID: <57480857.4070904@gmail.com>

Forget to send a patch, sorry for the noise.:-(
Please ignore this series patches [PATCH v4 0/4].

RESEND the new series patches "[RESEND PATCH v4 0/5]".

On 2016?05?27? 16:23, Caesar Wang wrote:
> The history patches come from Mikko and Sascha.
>      http://thread.gmane.org/gmane.linux.power-management.general/59451
>
> Now, I pick them up to continue upstream.
> Nevermind!
>
> This series history patches:
> v3: https://lkml.org/lkml/2016/5/24/797
> v2: https://lkml.org/lkml/2016/5/3/220
> v1: https://lkml.org/lkml/2016/4/24/227
>
> This series adds support for hardware trip points. It picks up earlier
> work from Mikko Perttunen. Mikko implemented hardware trip points as part
> of the device tree support. It was suggested back then to move the
> functionality to the thermal core instead of putting more code into the
> device tree support. This series does exactly that.
>
> This series patches rebase the conflicts.
> Note that the hardware-tracked trip points are very well tested currently.
>
> Verified and tested on https://github.com/Caesar-github/rockchip/tree/wip/fixes-thermal-0525
> That's based on linux-kernel 20160524.
>
>
> Changes in v4:
> - as the Javi comments, %s/implemnets/implements.
>
> Changes in v3:
> - as the Javi comments on https://patchwork.kernel.org/patch/9001311/.
> - add the select if they set the option for devicetree.
> - Add the peter's ACK.
>
> Changes in v2:
> - add the commit in patch[v2 2/5].
> - Update the commit for patch[v2 4/5].
>
> Caesar Wang (1):
>    thermal: rockchip: add the set_trips function
>
> Sascha Hauer (3):
>    thermal: of: implement .set_trips for device tree thermal zones
>    thermal: streamline get_trend callbacks
>    thermal: bang-bang governor: act on lower trip boundary
>
>   drivers/thermal/gov_bang_bang.c                    |  2 +-
>   drivers/thermal/of-thermal.c                       | 30 +++++++++++------
>   drivers/thermal/rockchip_thermal.c                 | 39 ++++++++++++++++++++++
>   drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 25 +++++---------
>   include/linux/thermal.h                            |  6 +++-
>   5 files changed, 73 insertions(+), 29 deletions(-)
>



From zyw at rock-chips.com  Fri May 27 01:46:07 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 16:46:07 +0800
Subject: [PATCH 2/6] Documentation: bindings: add dt doc for Rockchip USB
 Type-C PHY
In-Reply-To: <2812026.ptEv4ktvbn@phil>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
 <1464328939-8073-3-git-send-email-zyw@rock-chips.com>
 <2812026.ptEv4ktvbn@phil>
Message-ID: <5748094F.6030204@rock-chips.com>

Hi Heiko

On 05/27/2016 04:29 PM, Heiko Stuebner wrote:
> Hi Chris,
>
> Am Freitag, 27. Mai 2016, 14:02:15 schrieb Chris Zhong:
>> This patch adds a binding that describes the Rockchip USB Type-C PHY
>> for rk3399.
>>
>> Signed-off-by: Chris Zhong <zyw at rock-chips.com>
>> ---
>>
>>   .../devicetree/bindings/phy/phy-rockchip-typec.txt | 55
>> ++++++++++++++++++++++ 1 file changed, 55 insertions(+)
>>   create mode 100644
>> Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
>>
>> diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
>> b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file
>> mode 100644
>> index 0000000..402f667
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
>> @@ -0,0 +1,55 @@
>> +ROCKCHIP type-c PHY
>> +
>> +Required properties:
>> + - compatible: should be "rockchip,rk3399-typec-phy"
>> + - reg : Address and length of the usb phy control register set
>> + - rockchip,grf : phandle to the syscon managing the "general
>> +   register files"
>> + - clocks : phandle + clock specifier for the phy clocks
>> + - clock-names: string, clock name, must be "tcpdcore", "tcpdphy_ref";
>> + - resets : a list of phandle + reset specifier pairs
>> + - reset-names : string reset name, must be:
>> +		 "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst"
>> + - #phy-cells: Must be 0.  See ./phy-bindings.txt for details.
>> + - rockchip,usb3phy*: phy registers embed in grf
>> +
>> +Example:
>> +	tcphy0: phy at ff7c0000 {
>> +		compatible = "rockchip,rk3399-typec-phy";
>> +		reg = <0x0 0xff7c0000 0x0 0x40000>;
>> +		#phy-cells = <0>;
>> +		rockchip,grf = <&grf>;
>> +		clocks = <&cru SCLK_UPHY0_TCPDCORE>,
>> +			 <&cru SCLK_UPHY0_TCPDPHY_REF>;
>> +		clock-names = "tcpdcore", "tcpdphy_ref";
>> +		resets = <&cru SRST_UPHY0>,
>> +			 <&cru SRST_UPHY0_PIPE_L00>,
>> +			 <&cru SRST_P_UPHY0_TCPHY>;
>> +		reset-names = "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst";
>> +		rockchip,usb3phy_con0 = <0x0e580 0 16>;
>> +		rockchip,usb3phy_con1 = <0x0e584 0 16>;
>> +		rockchip,usb3phy_con2 = <0x0e588 0 16>;
>> +		rockchip,usb3phy_status0 = <0x0e5c0 0 13>;
>> +		rockchip,usb3phy_status1 = <0x0e5c4 0 12>;
> please embedded this register data in the driver instead (not in the
> devicetree), matched against the compatible value.
> See Frank's usb2phy driver for reference if needed.
Okay, I will move them to driver file next version, Thanks.
>
> Thanks
> Heiko
>
>
>
>




From wenrui.li at rock-chips.com  Fri May 27 03:31:28 2016
From: wenrui.li at rock-chips.com (Wenrui Li)
Date: Fri, 27 May 2016 18:31:28 +0800
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <8520D5D51A55D047800579B094147198258AF22F@XAP-PVEXMBX01.xlnx.xilinx.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
 <9836736.6VjP1ug4kE@wuerfel> <5747EDC9.2080603@rock-chips.com>
 <8520D5D51A55D047800579B094147198258AF22F@XAP-PVEXMBX01.xlnx.xilinx.com>
Message-ID: <57482200.9090008@rock-chips.com>

Hi,

On 2016/5/27 15:13, Bharat Kumar Gogada wrote:
>>>
>>>> +
>>>> +static int rockchip_pcie_rd_other_conf(struct rockchip_pcie_port *pp,
>>>> +				       struct pci_bus *bus, u32 devfn,
>>>> +				       int where, int size, u32 *val)
>>>> +{
>>>> +	u32 busdev;
>>>> +
>>>> +	busdev = PCIE_ECAM_ADDR(bus->number, PCI_SLOT(devfn),
>>>> +				PCI_FUNC(devfn), where);
>>>> +
>>>> +	if (busdev & (size - 1)) {
>>>> +		*val = 0;
>>>> +		return PCIBIOS_BAD_REGISTER_NUMBER;
>>>> +	}
>>>> +
>>>> +	if (size == 4) {
>>>> +		*val = readl(pp->reg_base + busdev);
>>>> +	} else if (size == 2) {
>>>> +		*val = readw(pp->reg_base + busdev);
>>>> +	} else if (size == 1) {
>>>> +		*val = readb(pp->reg_base + busdev);
>>>> +	} else {
>>>> +		*val = 0;
>>>> +		return PCIBIOS_BAD_REGISTER_NUMBER;
>>>> +	}
>>>> +	return PCIBIOS_SUCCESSFUL;
>>>> +}
>>>> +
>>>
>>> This looks like the normal ECAM operations, you could just call those.
>>
>> I read ECAM reference code, I found it not support ioremap config space
>> for each bus individually on 64-bit systems. Our soc is 64-bit system,
>> and bus0 config space base address is 0xfda00000, bus1 base address is
>> 0xf8100000. So I think it is not normal ECAM operations, I do not know
>> if I have understood correctly?
>>
> Hi,
>
> I think Arnd was suggesting to use generic config read/write calls, pci_generic_config_read/pci_generic_config_write
> which does above functionality.

Yeah, I seem the pci_generic_config_write use writew/writeb for byte and 
word write. but our SOC not support byte and word write in RC config 
spcace. So I redefine the the pci_ops.write

>
> Bharat
>
>
>



From zyw at rock-chips.com  Fri May 27 03:45:36 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 18:45:36 +0800
Subject: [RESEND PATCH 0/6] Rockchip Type-C and DispplayPort driver
Message-ID: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>

Sorry, forgot a head file in patch 1, so resend.

Hi all

This series patch is for rockchip Type-C phy and DisplayPort controller
driver.

The USB Type-C PHY is designed to support the USB3 and DP applications.
The PHY basically has two main components: USB3 and DisplyPort. USB3
operates in SuperSpeed mode and the DP can operate at RBR, HBR and HBR2
data rates. The Type-C cable orientation detection and Power Delivery
(PD) is accomplished using a PD PHY or a exernal PD chip.

The DP controller is compliant with DisplayPort Specification,
Version 1.3, This IP is compatible with the rockchip type-c PHY IP.
There is a uCPU in DP controller, it need a firmware to work, please
put the firmware file to /lib/firmware/cdn/dptx.bin. The uCPU in charge
of aux communication and link training, the host use mailbox to
communicate with the ucpu.

The PHY driver has register a notification, to get the alt mode from PD,
the PD driver need call the tcphy_notifier_call_chain to notify PHY and
DP controller.

This series is based on Mark Yao's branch:
https://github.com/markyzq/kernel-drm-rockchip/tree/drm-rockchip-next-2016-05-23

I test this patches on the rk3399-evb board, with a fusb302 driver,
this branch has no rk3399.dtsi, so the patch about dts is not included
in this series.



Chris Zhong (6):
  phy: Add USB Type-C PHY driver for rk3399
  Documentation: bindings: add dt doc for Rockchip USB Type-C PHY
  drm/rockchip: vop: add cdn DP support for rk3399
  Documentation: bindings: add dt documentation for cdn DP controller
  ASoC: cdn-dp: Add cdn DP codec driver
  ASoC: rockchip: Add machine driver for cdn dp codec

 .../bindings/display/rockchip/cdn-dp-rockchip.txt  |  57 ++
 .../devicetree/bindings/phy/phy-rockchip-typec.txt |  55 ++
 .../bindings/sound/rockchip-cdn-dp-audio.txt       |  12 +
 drivers/gpu/drm/rockchip/Kconfig                   |   9 +
 drivers/gpu/drm/rockchip/Makefile                  |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c             | 620 ++++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-core.h             |  95 +++
 drivers/gpu/drm/rockchip/cdn-dp-reg.c              | 730 ++++++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-reg.h              | 404 ++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |   9 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h        |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c        |   2 +
 drivers/phy/Kconfig                                |   7 +
 drivers/phy/Makefile                               |   1 +
 drivers/phy/phy-rockchip-typec.c                   | 823 +++++++++++++++++++++
 include/linux/phy/phy-rockchip-typec.h             |  72 ++
 include/sound/cdn-dp-audio.h                       |  51 ++
 sound/soc/codecs/Kconfig                           |   3 +
 sound/soc/codecs/Makefile                          |   2 +
 sound/soc/codecs/cdn-dp-audio.c                    | 246 ++++++
 sound/soc/rockchip/Kconfig                         |   9 +
 sound/soc/rockchip/Makefile                        |   2 +
 sound/soc/rockchip/rockchip-cdn-dp-audio.c         | 167 +++++
 23 files changed, 3378 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip-cdn-dp-audio.txt
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.h
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.h
 create mode 100644 drivers/phy/phy-rockchip-typec.c
 create mode 100644 include/linux/phy/phy-rockchip-typec.h
 create mode 100644 include/sound/cdn-dp-audio.h
 create mode 100644 sound/soc/codecs/cdn-dp-audio.c
 create mode 100644 sound/soc/rockchip/rockchip-cdn-dp-audio.c

-- 
2.6.3



From zyw at rock-chips.com  Fri May 27 03:45:37 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 18:45:37 +0800
Subject: [RESEND PATCH 1/6] phy: Add USB Type-C PHY driver for rk3399
In-Reply-To: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
References: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464345942-4795-2-git-send-email-zyw@rock-chips.com>

Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB
Type-C PHY is designed to support the USB3 and DP applications. The
PHY basically has two main components: USB3 and DisplyPort. USB3
operates in SuperSpeed mode and the DP can operate at RBR, HBR and
HBR2 data rates.

Signed-off-by: Chris Zhong <zyw at rock-chips.com>
---

 drivers/phy/Kconfig                    |   7 +
 drivers/phy/Makefile                   |   1 +
 drivers/phy/phy-rockchip-typec.c       | 823 +++++++++++++++++++++++++++++++++
 include/linux/phy/phy-rockchip-typec.h |  72 +++
 4 files changed, 903 insertions(+)
 create mode 100644 drivers/phy/phy-rockchip-typec.c
 create mode 100644 include/linux/phy/phy-rockchip-typec.h

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index 26566db..dc388a3d 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -351,6 +351,13 @@ config PHY_ROCKCHIP_DP
 	help
 	  Enable this to support the Rockchip Display Port PHY.
 
+config PHY_ROCKCHIP_TYPEC
+	tristate "Rockchip TYPEC PHY Driver"
+	depends on ARCH_ROCKCHIP && OF
+	select GENERIC_PHY
+	help
+	  Enable this to support the Rockchip USB TYPEC PHY.
+
 config PHY_ST_SPEAR1310_MIPHY
 	tristate "ST SPEAR1310-MIPHY driver"
 	select GENERIC_PHY
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 24596a9..91fa413 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -39,6 +39,7 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
 obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
 obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
 obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
+obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
 obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
 obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)	+= phy-spear1310-miphy.o
 obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)	+= phy-spear1340-miphy.o
diff --git a/drivers/phy/phy-rockchip-typec.c b/drivers/phy/phy-rockchip-typec.c
new file mode 100644
index 0000000..6609cfb
--- /dev/null
+++ b/drivers/phy/phy-rockchip-typec.c
@@ -0,0 +1,823 @@
+/*
+ * Rockchip usb3 PHY driver
+ *
+ * Copyright (C) 2016 Kever Yang <kever.yang at rock-chips.com>
+ *                    Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/reset.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/delay.h>
+#include <linux/phy/phy-rockchip-typec.h>
+
+#define ADDR_ADJ			2
+#define CMN_SSM_BANDGAP			(0x21 << ADDR_ADJ)
+#define CMN_SSM_BIAS			(0x22 << ADDR_ADJ)
+#define CMN_PLLSM0_PLLEN		(0x29 << ADDR_ADJ)
+#define CMN_PLLSM0_PLLPRE		(0x2a << ADDR_ADJ)
+#define CMN_PLLSM0_PLLVREF		(0x2b << ADDR_ADJ)
+#define CMN_PLLSM0_PLLLOCK		(0x2c << ADDR_ADJ)
+#define CMN_PLLSM1_PLLEN		(0x31 << ADDR_ADJ)
+#define CMN_PLLSM1_PLLPRE		(0x32 << ADDR_ADJ)
+#define CMN_PLLSM1_PLLVREF		(0x33 << ADDR_ADJ)
+#define CMN_PLLSM1_PLLLOCK		(0x34 << ADDR_ADJ)
+#define CMN_PLLSM1_USER_DEF_CTRL	(0x37 << ADDR_ADJ)
+#define CMN_ICAL_OVRD			(0xc1 << ADDR_ADJ)
+#define CMN_PLL0_VCOCAL_OVRD		(0x83 << ADDR_ADJ)
+#define CMN_PLL0_VCOCAL_INIT		(0x84 << ADDR_ADJ)
+#define CMN_PLL0_VCOCAL_ITER		(0x85 << ADDR_ADJ)
+#define CMN_PLL0_LOCK_REFCNT_START	(0x90 << ADDR_ADJ)
+#define CMN_PLL0_LOCK_PLLCNT_START	(0x92 << ADDR_ADJ)
+#define CMN_PLL0_LOCK_PLLCNT_THR	(0x93 << ADDR_ADJ)
+#define CMN_PLL0_INTDIV			(0x94 << ADDR_ADJ)
+#define CMN_PLL0_FRACDIV		(0x95 << ADDR_ADJ)
+#define CMN_PLL0_HIGH_THR		(0x96 << ADDR_ADJ)
+#define CMN_PLL0_DSM_DIAG		(0x97 << ADDR_ADJ)
+#define CMN_PLL0_SS_CTRL1		(0x98 << ADDR_ADJ)
+#define CMN_PLL0_SS_CTRL2		(0x99 << ADDR_ADJ)
+#define CMN_PLL1_VCOCAL_START		(0xa1 << ADDR_ADJ)
+#define CMN_PLL1_VCOCAL_OVRD		(0xa3 << ADDR_ADJ)
+#define CMN_PLL1_VCOCAL_INIT		(0xa4 << ADDR_ADJ)
+#define CMN_PLL1_VCOCAL_ITER		(0xa5 << ADDR_ADJ)
+#define CMN_PLL1_LOCK_REFCNT_START	(0xb0 << ADDR_ADJ)
+#define CMN_PLL1_LOCK_PLLCNT_START	(0xb2 << ADDR_ADJ)
+#define CMN_PLL1_LOCK_PLLCNT_THR	(0xb3 << ADDR_ADJ)
+#define CMN_PLL1_INTDIV			(0xb4 << ADDR_ADJ)
+#define CMN_PLL1_FRACDIV		(0xb5 << ADDR_ADJ)
+#define CMN_PLL1_HIGH_THR		(0xb6 << ADDR_ADJ)
+#define CMN_PLL1_DSM_DIAG		(0xb7 << ADDR_ADJ)
+#define CMN_PLL1_SS_CTRL1		(0xb8 << ADDR_ADJ)
+#define CMN_PLL1_SS_CTRL2		(0xb9 << ADDR_ADJ)
+#define CMN_RXCAL_OVRD			(0xd1 << ADDR_ADJ)
+#define CMN_TXPUCAL_CTRL		(0xe0 << ADDR_ADJ)
+#define CMN_TXPUCAL_OVRD		(0xe1 << ADDR_ADJ)
+#define CMN_TXPDCAL_OVRD		(0xf1 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_FBH_OVRD		(0x1c0 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_FBL_OVRD		(0x1c1 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_OVRD		(0x1c2 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_V2I_TUNE		(0x1c5 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_CP_TUNE		(0x1c6 << ADDR_ADJ)
+#define CMN_DIAG_PLL0_LF_PROG		(0x1c7 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_FBH_OVRD		(0x1d0 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_FBL_OVRD		(0x1d1 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_OVRD		(0x1d2 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_V2I_TUNE		(0x1d5 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_CP_TUNE		(0x1d6 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_LF_PROG		(0x1d7 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_PTATIS_TUNE1	(0x1d8 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_PTATIS_TUNE2	(0x1d9 << ADDR_ADJ)
+#define CMN_DIAG_PLL1_INCLK_CTRL	(0x1da << ADDR_ADJ)
+#define CMN_DIAG_HSCLK_SEL		(0x1e0 << ADDR_ADJ)
+
+#define XCVR_PSM_RCTRL(n)		((0x4001 | (n << 9)) << ADDR_ADJ)
+#define XCVR_PSM_CAL_TMR(n)		((0x4002 | (n << 9)) << ADDR_ADJ)
+#define XCVR_PSM_A0IN_TMR(n)		((0x4003 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_CAL_SCLR_MULT(n)	((0x4047 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_CPOST_MULT_00(n)	((0x404c | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_CPOST_MULT_01(n)	((0x404d | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_CPOST_MULT_10(n)	((0x404e | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_CPOST_MULT_11(n)	((0x404f | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_000(n)	((0x4050 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_001(n)	((0x4051 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_010(n)	((0x4052 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_011(n)	((0x4053 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_100(n)	((0x4054 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_101(n)	((0x4055 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_110(n)	((0x4056 | (n << 9)) << ADDR_ADJ)
+#define TX_TXCC_MGNFS_MULT_111(n)	((0x4057 | (n << 9)) << ADDR_ADJ)
+#define XCVR_DIAG_PLLDRC_CTRL(n)	((0x40e0 | (n << 9)) << ADDR_ADJ)
+#define XCVR_DIAG_BIDI_CTRL(n)		((0x40e8 | (n << 9)) << ADDR_ADJ)
+#define XCVR_DIAG_LANE_FCM_EN_MGN(n)	((0x40f2 | (n << 9)) << ADDR_ADJ)
+#define TX_PSC_A0(n)			((0x4100 | (n << 9)) << ADDR_ADJ)
+#define TX_PSC_A1(n)			((0x4101 | (n << 9)) << ADDR_ADJ)
+#define TX_PSC_A2(n)			((0x4102 | (n << 9)) << ADDR_ADJ)
+#define TX_PSC_A3(n)			((0x4103 | (n << 9)) << ADDR_ADJ)
+#define TX_RCVDET_CTRL(n)		((0x4120 | (n << 9)) << ADDR_ADJ)
+#define TX_RCVDET_EN_TMR(n)		((0x4122 | (n << 9)) << ADDR_ADJ)
+#define TX_RCVDET_ST_TMR(n)		((0x4123 | (n << 9)) << ADDR_ADJ)
+#define TX_DIAG_TX_DRV(n)		((0x41e1 | (n << 9)) << ADDR_ADJ)
+#define TX_DIAG_BGREF_PREDRV_DELAY	(0x41e7 << ADDR_ADJ)
+#define TX_ANA_CTRL_REG_1		(0x5020 << ADDR_ADJ)
+#define TX_ANA_CTRL_REG_2		(0x5021 << ADDR_ADJ)
+#define TXDA_COEFF_CALC_CTRL		(0x5022 << ADDR_ADJ)
+#define TX_DIG_CTRL_REG_2		(0x5024 << ADDR_ADJ)
+#define TXDA_CYA_AUXDA_CYA		(0x5025 << ADDR_ADJ)
+#define TX_ANA_CTRL_REG_3		(0x5026 << ADDR_ADJ)
+#define TX_ANA_CTRL_REG_4		(0x5027 << ADDR_ADJ)
+#define TX_ANA_CTRL_REG_5		(0x5029 << ADDR_ADJ)
+
+#define RX_PSC_A0(n)			((0x8000 | (n << 9)) << ADDR_ADJ)
+#define RX_PSC_A1(n)			((0x8001 | (n << 9)) << ADDR_ADJ)
+#define RX_PSC_A2(n)			((0x8002 | (n << 9)) << ADDR_ADJ)
+#define RX_PSC_A3(n)			((0x8003 | (n << 9)) << ADDR_ADJ)
+#define RX_PSC_CAL(n)			((0x8006 | (n << 9)) << ADDR_ADJ)
+#define RX_PSC_RDY(n)			((0x8007 | (n << 9)) << ADDR_ADJ)
+#define RX_IQPI_ILL_CAL_OVRD		(0x8023 << ADDR_ADJ)
+#define RX_EPI_ILL_CAL_OVRD		(0x8033 << ADDR_ADJ)
+#define RX_SDCAL0_OVRD			(0x8041 << ADDR_ADJ)
+#define RX_SDCAL1_OVRD			(0x8049 << ADDR_ADJ)
+#define RX_SLC_INIT			(0x806d << ADDR_ADJ)
+#define RX_SLC_RUN			(0x806e << ADDR_ADJ)
+#define RX_CDRLF_CNFG2			(0x8081 << ADDR_ADJ)
+#define RX_SIGDET_HL_FILT_TMR(n)	((0x8090 | (n << 9)) << ADDR_ADJ)
+#define RX_SLC_IOP0_OVRD		(0x8101 << ADDR_ADJ)
+#define RX_SLC_IOP1_OVRD		(0x8105 << ADDR_ADJ)
+#define RX_SLC_QOP0_OVRD		(0x8109 << ADDR_ADJ)
+#define RX_SLC_QOP1_OVRD		(0x810d << ADDR_ADJ)
+#define RX_SLC_EOP0_OVRD		(0x8111 << ADDR_ADJ)
+#define RX_SLC_EOP1_OVRD		(0x8115 << ADDR_ADJ)
+#define RX_SLC_ION0_OVRD		(0x8119 << ADDR_ADJ)
+#define RX_SLC_ION1_OVRD		(0x811d << ADDR_ADJ)
+#define RX_SLC_QON0_OVRD		(0x8121 << ADDR_ADJ)
+#define RX_SLC_QON1_OVRD		(0x8125 << ADDR_ADJ)
+#define RX_SLC_EON0_OVRD		(0x8129 << ADDR_ADJ)
+#define RX_SLC_EON1_OVRD		(0x812d << ADDR_ADJ)
+#define RX_SLC_IEP0_OVRD		(0x8131 << ADDR_ADJ)
+#define RX_SLC_IEP1_OVRD		(0x8135 << ADDR_ADJ)
+#define RX_SLC_QEP0_OVRD		(0x8139 << ADDR_ADJ)
+#define RX_SLC_QEP1_OVRD		(0x813d << ADDR_ADJ)
+#define RX_SLC_EEP0_OVRD		(0x8141 << ADDR_ADJ)
+#define RX_SLC_EEP1_OVRD		(0x8145 << ADDR_ADJ)
+#define RX_SLC_IEN0_OVRD		(0x8149 << ADDR_ADJ)
+#define RX_SLC_IEN1_OVRD		(0x814d << ADDR_ADJ)
+#define RX_SLC_QEN0_OVRD		(0x8151 << ADDR_ADJ)
+#define RX_SLC_QEN1_OVRD		(0x8155 << ADDR_ADJ)
+#define RX_SLC_EEN0_OVRD		(0x8159 << ADDR_ADJ)
+#define RX_SLC_EEN1_OVRD		(0x815d << ADDR_ADJ)
+#define RX_DIAG_SIGDET_TUNE(n)		((0x81dc | (n << 9)) << ADDR_ADJ)
+#define RX_DIAG_SC2C_DELAY		(0x81e1 << ADDR_ADJ)
+
+#define PMA_LANE_CFG			(0xc000 << ADDR_ADJ)
+#define PIPE_CMN_CTRL1			(0xc001 << ADDR_ADJ)
+#define PIPE_CMN_CTRL2			(0xc002 << ADDR_ADJ)
+#define PIPE_COM_LOCK_CFG1		(0xc003 << ADDR_ADJ)
+#define PIPE_COM_LOCK_CFG2		(0xc004 << ADDR_ADJ)
+#define PIPE_RCV_DET_INH		(0xc005 << ADDR_ADJ)
+#define DP_MODE_CTL			(0xc008 << ADDR_ADJ)
+#define DP_CLK_CTL			(0xc009 << ADDR_ADJ)
+#define STS				(0xc00F << ADDR_ADJ)
+#define PHY_ISO_CMN_CTRL		(0xc010 << ADDR_ADJ)
+#define PHY_DP_TX_CTL			(0xc408 << ADDR_ADJ)
+#define PMA_CMN_CTRL1			(0xc800 << ADDR_ADJ)
+#define PHY_PMA_ISO_CMN_CTRL		(0xc810 << ADDR_ADJ)
+#define PHY_ISOLATION_CTRL		(0xc81f << ADDR_ADJ)
+#define PHY_PMA_ISO_XCVR_CTRL(n)	((0xcc11 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_LINK_MODE(n)	((0xcc12 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_PWRST_CTRL(n)	((0xcc13 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_TX_DATA_LO(n)	((0xcc14 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_TX_DATA_HI(n)	((0xcc15 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_RX_DATA_LO(n)	((0xcc16 | (n << 6)) << ADDR_ADJ)
+#define PHY_PMA_ISO_RX_DATA_HI(n)	((0xcc17 | (n << 6)) << ADDR_ADJ)
+#define TX_BIST_CTRL(n)			((0x4140 | (n << 9)) << ADDR_ADJ)
+#define TX_BIST_UDDWR(n)		((0x4141 | (n << 9)) << ADDR_ADJ)
+
+#define GRF_SOC_CON26			0x6268
+#define UPHY_DP_SEL			BIT(3)
+#define UPHY_DP_SEL_MASK		BIT(19)
+#define DPTX_HDP_SEL			(3 << 12)
+#define DPTX_HDP_SEL_MASK		(3 << 28)
+
+#define PHY_MODE_SET_TIMEOUT		1000000
+
+#define	MODE_DISCONNECT			1
+#define	MODE_UFP			2
+#define	MODE_DFP_USBONLY		3
+#define	MODE_DFP_DPONLY			4
+#define	MODE_DFP_USB3DP			5
+#define	MODE_DFP_USB2DP			6
+
+#define PARSE_GRF_REG(TYPE) { \
+	if (of_find_property(np, "rockchip,usb3phy_"#TYPE, &len)) { \
+		len /= sizeof(u32);\
+		ret = of_property_read_u32_array(np, "rockchip,usb3phy_" #TYPE,\
+						 array, len); \
+		exregs->usb3phy_##TYPE = array[0]; \
+		exregs->usb3phy_##TYPE##_shift = array[1]; \
+		exregs->usb3phy_##TYPE##_mask = array[2]; \
+		pr_info("%s property found %s, %x, %d, %d\n", __func__, \
+			"rockchip,usb3phy_"#TYPE, \
+			array[0], array[1], array[2]); \
+	} else { \
+		pr_info("%s property not found %s\n", __func__, \
+			"rockchip,usb3phy_" #TYPE); \
+	} \
+}
+
+struct rockchip_typec_phy *rockchip_tcphy;
+
+static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy,
+			  unsigned int num_lanes)
+{
+	unsigned int i;
+
+	writel(0x830, tcphy->base + PMA_CMN_CTRL1);
+	for (i = 0; i < num_lanes; i++) {
+		writel(0x90, tcphy->base + XCVR_DIAG_LANE_FCM_EN_MGN(i));
+		writel(0x960, tcphy->base + TX_RCVDET_EN_TMR(i));
+		writel(0x30, tcphy->base + TX_RCVDET_ST_TMR(i));
+	}
+}
+
+static void tcphy_cfg_usb_pll(struct rockchip_typec_phy *tcphy)
+{
+	unsigned int rdata;
+
+	rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
+	writel(rdata & 0xfffc, tcphy->base + CMN_DIAG_HSCLK_SEL);
+	writel(0xf0, tcphy->base + CMN_PLL0_VCOCAL_INIT);
+	writel(0x18, tcphy->base + CMN_PLL0_VCOCAL_ITER);
+	writel(0xd0, tcphy->base + CMN_PLL0_INTDIV);
+	writel(0x4a4a, tcphy->base + CMN_PLL0_FRACDIV);
+	writel(0x34, tcphy->base + CMN_PLL0_HIGH_THR);
+	writel(0x1ee, tcphy->base + CMN_PLL0_SS_CTRL1);
+	writel(0x7f03, tcphy->base + CMN_PLL0_SS_CTRL2);
+	writel(0x20, tcphy->base + CMN_PLL0_DSM_DIAG);
+	writel(0, tcphy->base + CMN_DIAG_PLL0_OVRD);
+	writel(0, tcphy->base + CMN_DIAG_PLL0_FBH_OVRD);
+	writel(0, tcphy->base + CMN_DIAG_PLL0_FBL_OVRD);
+	writel(0x7, tcphy->base + CMN_DIAG_PLL0_V2I_TUNE);
+	writel(0x45, tcphy->base + CMN_DIAG_PLL0_CP_TUNE);
+	writel(0x8, tcphy->base + CMN_DIAG_PLL0_LF_PROG);
+}
+
+static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy)
+{
+	unsigned int rdata;
+
+	writel(0x2405, tcphy->base + DP_CLK_CTL);
+
+	rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
+	rdata = (rdata & 0xffcf) | 0x30;
+	writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL);
+	writel(0xf0, tcphy->base + CMN_PLL1_VCOCAL_INIT);
+	writel(0x18, tcphy->base + CMN_PLL1_VCOCAL_ITER);
+	writel(0x30b9, tcphy->base + CMN_PLL1_VCOCAL_START);
+	writel(0x21c, tcphy->base + CMN_PLL1_INTDIV);
+	writel(0, tcphy->base + CMN_PLL1_FRACDIV);
+	writel(0x5, tcphy->base + CMN_PLL1_HIGH_THR);
+	writel(0x35, tcphy->base + CMN_PLL1_SS_CTRL1);
+	writel(0x7f1e, tcphy->base + CMN_PLL1_SS_CTRL2);
+	writel(0x20, tcphy->base + CMN_PLL1_DSM_DIAG);
+	writel(0, tcphy->base + CMN_PLLSM1_USER_DEF_CTRL);
+	writel(0, tcphy->base + CMN_DIAG_PLL1_OVRD);
+	writel(0, tcphy->base + CMN_DIAG_PLL1_FBH_OVRD);
+	writel(0, tcphy->base + CMN_DIAG_PLL1_FBL_OVRD);
+	writel(0x6, tcphy->base + CMN_DIAG_PLL1_V2I_TUNE);
+	writel(0x45, tcphy->base + CMN_DIAG_PLL1_CP_TUNE);
+	writel(0x8, tcphy->base + CMN_DIAG_PLL1_LF_PROG);
+	writel(0x100, tcphy->base + CMN_DIAG_PLL1_PTATIS_TUNE1);
+	writel(0x7, tcphy->base + CMN_DIAG_PLL1_PTATIS_TUNE2);
+	writel(0x4, tcphy->base + CMN_DIAG_PLL1_INCLK_CTRL);
+}
+
+static void tcphy_tx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
+				  unsigned int lane)
+{
+	writel(0x7799, tcphy->base + TX_PSC_A0(lane));
+	writel(0x7798, tcphy->base + TX_PSC_A1(lane));
+	writel(0x5098, tcphy->base + TX_PSC_A2(lane));
+	writel(0x5098, tcphy->base + TX_PSC_A3(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
+	writel(0xbf, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
+}
+
+static void tcphy_rx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
+				  unsigned int lane)
+{
+	writel(0xa6fd, tcphy->base + RX_PSC_A0(lane));
+	writel(0xa6fd, tcphy->base + RX_PSC_A1(lane));
+	writel(0xa410, tcphy->base + RX_PSC_A2(lane));
+	writel(0x2410, tcphy->base + RX_PSC_A3(lane));
+	writel(0x23ff, tcphy->base + RX_PSC_CAL(lane));
+	writel(0x13, tcphy->base + RX_SIGDET_HL_FILT_TMR(lane));
+	writel(0x1004, tcphy->base + RX_DIAG_SIGDET_TUNE(lane));
+	writel(0x2010, tcphy->base + RX_PSC_RDY(lane));
+	writel(0xfb, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
+}
+
+static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy,
+			      unsigned int lane)
+{
+	unsigned int rdata;
+
+	writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane));
+	writel(0x6799, tcphy->base + TX_PSC_A0(lane));
+	writel(0x6798, tcphy->base + TX_PSC_A1(lane));
+	writel(0x98, tcphy->base + TX_PSC_A2(lane));
+	writel(0x98, tcphy->base + TX_PSC_A3(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_001(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_010(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_011(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_100(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_101(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_110(lane));
+	writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_111(lane));
+
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_10(lane));
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_01(lane));
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_00(lane));
+	writel(0, tcphy->base + TX_TXCC_CPOST_MULT_11(lane));
+
+	writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane));
+	writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane));
+
+	rdata = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
+	rdata = (rdata & 0x8fff) | 0x6000;
+	writel(rdata, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
+}
+
+static void tcphy_cfg_pin_assign(struct rockchip_typec_phy *tcphy)
+{
+	switch (tcphy->map) {
+	case PIN_MAP_A:
+		writel(0x19d5, tcphy->base + PMA_LANE_CFG);
+		break;
+	case PIN_MAP_B:
+		writel(0x1500, tcphy->base + PMA_LANE_CFG);
+		break;
+	case PIN_MAP_C:
+	case PIN_MAP_E:
+		writel(0x51d9, tcphy->base + PMA_LANE_CFG);
+		break;
+	case PIN_MAP_D:
+	case PIN_MAP_F:
+		writel(0x5100, tcphy->base + PMA_LANE_CFG);
+		break;
+	};
+}
+
+static void tcphy_cfg_lanes(struct rockchip_typec_phy *tcphy,
+			    unsigned int link_cfg)
+{
+	unsigned int i;
+
+	/* PMA lane configuration DP or USB3 */
+	for (i = 0; i < 4; i++) {
+		if ((link_cfg >> i) & 0x1) {
+			tcphy_dp_cfg_lane(tcphy, i);
+		} else {
+			/*
+			 * lan0 TX and lan1 RX for USB3 Normal direction
+			 * lan3 TX and lan2 RX for USB3 Flip direction
+			 */
+			if ((i == 0) | (i == 3))
+				tcphy_tx_usb_cfg_lane(tcphy, i);
+			else
+				tcphy_rx_usb_cfg_lane(tcphy, i);
+		}
+	}
+}
+
+static void tcphy_cfg_flip_set(struct rockchip_typec_phy *tcphy)
+{
+	regmap_write(tcphy->grf_regs,
+		     tcphy->exregs.usb3phy_con0,
+		     tcphy->flip | BIT(16));
+
+	tcphy_cfg_24m(tcphy, 0x4);
+
+	if (tcphy->mode == MODE_UFP ||
+	    tcphy->mode == MODE_DFP_USBONLY ||
+	    tcphy->mode == MODE_DFP_USB3DP)
+		tcphy_cfg_usb_pll(tcphy);
+
+	if (tcphy->mode == MODE_DFP_DPONLY ||
+	    tcphy->mode == MODE_DFP_USB2DP ||
+	    tcphy->mode == MODE_DFP_USB3DP)
+		tcphy_cfg_dp_pll(tcphy);
+
+	if (tcphy->mode == MODE_DFP_DPONLY || tcphy->mode == MODE_DFP_USB2DP)
+		tcphy_cfg_lanes(tcphy, 0xf);
+	else if (tcphy->flip)
+		tcphy_cfg_lanes(tcphy, 0x3);
+	else
+		tcphy_cfg_lanes(tcphy, 0xc);
+}
+
+static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
+{
+	int rdata, rdata2, val;
+
+	rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
+	rdata2 = readl(tcphy->base + CMN_TXPUCAL_CTRL);
+
+	rdata = rdata & 0xdfff;
+	writel(rdata, tcphy->base + TX_ANA_CTRL_REG_1);
+
+	rdata = readl(tcphy->base + TX_DIG_CTRL_REG_2);
+	rdata = rdata & 0xffc0;
+	rdata2 = rdata2 & 0x3f;
+	rdata  = rdata | rdata2;
+	writel(rdata, tcphy->base + TX_DIG_CTRL_REG_2);
+	usleep_range(1000, 2000);
+
+	rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
+	rdata = rdata | 0x2000;
+	writel(rdata, tcphy->base + TX_ANA_CTRL_REG_1);
+
+	usleep_range(150, 200);
+
+	writel(0, tcphy->base + PHY_DP_TX_CTL);
+	writel(0x100, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0x300, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
+	writel(0x2008, tcphy->base + TX_ANA_CTRL_REG_1);
+	writel(0x2018, tcphy->base + TX_ANA_CTRL_REG_1);
+	writel(0x30C, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
+	writel(0x1001, tcphy->base + TX_ANA_CTRL_REG_4);
+	writel(0x2098, tcphy->base + TX_ANA_CTRL_REG_1);
+	writel(0x2198, tcphy->base + TX_ANA_CTRL_REG_1);
+	writel(0x30d, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0x30f, tcphy->base + TX_ANA_CTRL_REG_2);
+
+	if (tcphy->flip)
+		writel(0xa078, tcphy->base + TX_ANA_CTRL_REG_1);
+	else
+		writel(0xb078, tcphy->base + TX_ANA_CTRL_REG_1);
+
+	writel(0x303, tcphy->base + TX_ANA_CTRL_REG_2);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_4);
+	writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
+	writel(4, tcphy->base + TXDA_COEFF_CALC_CTRL);
+	writel(0, tcphy->base + TXDA_CYA_AUXDA_CYA);
+
+	val = readl(tcphy->base + TX_DIG_CTRL_REG_2);
+	val |= BIT(15);
+	writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
+}
+
+static void tcphy_dp_hpd(struct rockchip_typec_phy *tcphy,
+			 u8 mode)
+{
+	/* force hpd */
+	if (mode)
+		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+			     DPTX_HDP_SEL_MASK | DPTX_HDP_SEL);
+	else
+		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+			     DPTX_HDP_SEL_MASK);
+}
+
+static int tcphy_usb3_init(struct rockchip_typec_phy *tcphy)
+{
+	int timeout = 0;
+	int ret, val;
+
+	/*wait TCPHY for pipe ready */
+	while (1) {
+		ret = regmap_read(tcphy->grf_regs,
+				  tcphy->exregs.usb3phy_status0, &val);
+		val >>= tcphy->exregs.usb3phy_status0_shift;
+		if ((val & 0x1) == 0)
+			break;
+
+		timeout++;
+		if (timeout > 1000) {
+			pr_warn("%s wait pipe ready timerout!\n", __func__);
+			break;
+		}
+		usleep_range(10, 20);
+	}
+
+	return 0;
+}
+
+static int tcphy_dp_init(struct rockchip_typec_phy *tcphy)
+{
+	int ret, val;
+
+	ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
+				 val, val & BIT(6), 1000, PHY_MODE_SET_TIMEOUT);
+	if (ret < 0) {
+		dev_err(tcphy->dev, "failed to wait TCPHY for DP ready\n");
+		return -EBUSY;
+	}
+
+	tcphy_dp_aux_calibration(tcphy);
+
+	if (tcphy->mode == MODE_DFP_USB3DP)
+		writel(0xc101, tcphy->base + DP_MODE_CTL);
+	else
+		writel(0x0101, tcphy->base + DP_MODE_CTL);
+
+	ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
+				 val, val & BIT(4), 1000, PHY_MODE_SET_TIMEOUT);
+	if (ret < 0) {
+		dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n");
+		return -EBUSY;
+	}
+
+	return 0;
+}
+
+static int tcphy_phy_init(struct rockchip_typec_phy *tcphy)
+{
+	int ret;
+	int timeout = 0;
+
+	ret = clk_prepare_enable(tcphy->clk_core);
+	if (ret) {
+		dev_err(tcphy->dev, "Failed to prepare_enable core clock\n");
+		return ret;
+	}
+
+	ret = clk_prepare_enable(tcphy->clk_ref);
+	if (ret) {
+		dev_err(tcphy->dev, "Failed to prepare_enable ref clock\n");
+		return ret;
+	}
+
+	/* select external psm clock */
+	regmap_write(tcphy->grf_regs, tcphy->exregs.usb3phy_con2,
+		     BIT(14) | BIT(30));
+	regmap_write(tcphy->grf_regs, tcphy->exregs.usb3phy_con0, BIT(19));
+
+	reset_control_assert(tcphy->phy_rst);
+	reset_control_assert(tcphy->pipe_rst);
+	reset_control_assert(tcphy->uphy_rst);
+
+	if (tcphy->num == TYPEC_PHY0)
+		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+			     UPHY_DP_SEL_MASK);
+	else
+		regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
+			     UPHY_DP_SEL_MASK | UPHY_DP_SEL);
+
+	reset_control_deassert(tcphy->uphy_rst);
+
+	tcphy_cfg_flip_set(tcphy);
+
+	tcphy_cfg_pin_assign(tcphy);
+
+	if (tcphy->mode == MODE_DFP_USB3DP)
+		writel(0xc104, tcphy->base + DP_MODE_CTL);
+	else if ((tcphy->mode == MODE_DFP_DPONLY) ||
+		 (tcphy->mode == MODE_DFP_USB2DP))
+		writel(0x0104, tcphy->base + DP_MODE_CTL);
+
+	reset_control_deassert(tcphy->phy_rst);
+
+	while (!(readl(tcphy->base + PMA_CMN_CTRL1) & 1)) {
+		timeout++;
+		if (timeout > 1000)
+			break;
+		usleep_range(10, 20);
+	}
+
+	reset_control_deassert(tcphy->pipe_rst);
+
+	return 0;
+}
+
+static int tcphy_phy_deinit(struct rockchip_typec_phy *tcphy)
+{
+	clk_disable_unprepare(tcphy->clk_core);
+	clk_disable_unprepare(tcphy->clk_ref);
+
+	return 0;
+}
+
+int tcphy_register_notifier(struct phy *_phy, struct notifier_block *nb)
+{
+	struct rockchip_typec_phy *tcphy = phy_get_drvdata(_phy);
+
+	return atomic_notifier_chain_register(&tcphy->notifier, nb);
+}
+
+void tcphy_unregister_notifier(struct phy *_phy,
+			       struct notifier_block *nb)
+{
+	struct rockchip_typec_phy *tcphy = phy_get_drvdata(_phy);
+
+	atomic_notifier_chain_unregister(&tcphy->notifier, nb);
+}
+
+void tcphy_notifier_call_chain(struct rockchip_typec_phy *x,
+			       unsigned long val, void *v)
+{
+	atomic_notifier_call_chain(&x->notifier, val, v);
+}
+EXPORT_SYMBOL_GPL(tcphy_notifier_call_chain);
+
+static int tcphy_pd_event(struct notifier_block *nb,
+			  unsigned long event, void *priv)
+{
+	struct rockchip_typec_phy *tcphy;
+	int value = *(int *)priv;
+	u8 is_dp, dfp;
+
+	tcphy = container_of(nb, struct rockchip_typec_phy, event_nb);
+	if (IS_ERR_OR_NULL(tcphy)) {
+		pr_err("initialization issue");
+		return -1;
+	}
+
+	tcphy->flip = GET_FLIP(value);
+	dfp = GET_DFP(value);
+	is_dp = GET_DP(value);
+	tcphy->map = GET_PIN_MAP(value);
+
+	if (event == 0) {
+		if (tcphy->mode == MODE_DISCONNECT)
+			return 0;
+		tcphy->mode = MODE_DISCONNECT;
+	} else if (is_dp) {
+		if (tcphy->map & (PIN_MAP_B | PIN_MAP_D | PIN_MAP_F))
+			tcphy->mode = MODE_DFP_USB3DP;
+		else
+			tcphy->mode = MODE_DFP_DPONLY;
+	} else if (dfp) {
+		tcphy->mode = MODE_DFP_USBONLY;
+	} else {
+		tcphy->mode = MODE_UFP;
+	}
+
+	schedule_delayed_work_on(0, &tcphy->event_wq, 0);
+
+	return 0;
+}
+
+static void tcphy_event_wq(struct work_struct *work)
+{
+	struct rockchip_typec_phy *tcphy;
+
+	tcphy = container_of(work, struct rockchip_typec_phy, event_wq.work);
+	if (IS_ERR_OR_NULL(tcphy)) {
+		pr_err("initialization issue");
+		return;
+	}
+
+	switch (tcphy->mode) {
+	case MODE_DISCONNECT:
+		/* phy enter low power mode */
+		tcphy_phy_deinit(tcphy);
+		tcphy_dp_hpd(tcphy, 0);
+		break;
+	case MODE_UFP:
+		tcphy_phy_init(tcphy);
+		tcphy_usb3_init(tcphy);
+		tcphy_dp_hpd(tcphy, 0);
+		break;
+	case MODE_DFP_USBONLY:
+		tcphy_phy_init(tcphy);
+		tcphy_usb3_init(tcphy);
+		tcphy_dp_hpd(tcphy, 0);
+		break;
+	case MODE_DFP_DPONLY:
+	case MODE_DFP_USB2DP:
+		tcphy_phy_init(tcphy);
+		tcphy_dp_init(tcphy);
+		tcphy_dp_hpd(tcphy, 1);
+		break;
+	case MODE_DFP_USB3DP:
+		tcphy_phy_init(tcphy);
+		tcphy_usb3_init(tcphy);
+		tcphy_dp_init(tcphy);
+		tcphy_dp_hpd(tcphy, 1);
+		break;
+	}
+}
+
+int tcphy_parse_reg(struct rockchip_typec_phy *tcphy, struct device *dev)
+{
+	struct tcphy_grf_reg *exregs = &tcphy->exregs;
+	struct device_node *np = dev->of_node;
+	u32 len = 0, array[3];
+	int ret = 0;
+
+	PARSE_GRF_REG(con0);
+	PARSE_GRF_REG(con1);
+	PARSE_GRF_REG(con2);
+	PARSE_GRF_REG(status0);
+	PARSE_GRF_REG(status1);
+	return ret;
+}
+
+static int rockchip_typec_phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct rockchip_typec_phy *tcphy;
+	struct resource *res;
+	struct phy_provider *phy_provider;
+
+	tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
+	if (!tcphy)
+		return -ENOMEM;
+
+	tcphy->dev = dev;
+	platform_set_drvdata(pdev, tcphy);
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	tcphy->base = devm_ioremap_resource(dev, res);
+	if (IS_ERR(tcphy->base)) {
+		dev_err(dev, "failed to remap phy regs\n");
+		return PTR_ERR(tcphy->base);
+	}
+	tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node,
+							"rockchip,grf");
+	if (IS_ERR(tcphy->grf_regs)) {
+		dev_err(dev, "%s: could not find grf dt node\n", __func__);
+		return PTR_ERR(tcphy->grf_regs);
+	}
+
+	tcphy->clk_core = of_clk_get_by_name(dev->of_node, "tcpdcore");
+	if (IS_ERR(tcphy->clk_core)) {
+		dev_err(dev, "%s: could not get uphy core clock\n", __func__);
+		tcphy->clk_core = NULL;
+	}
+
+	tcphy->clk_ref = of_clk_get_by_name(dev->of_node, "tcpdphy_ref");
+	if (IS_ERR(tcphy->clk_core)) {
+		dev_err(dev, "%s: could not get uphy ref clock\n", __func__);
+		tcphy->clk_core = NULL;
+	}
+
+	tcphy->phy_rst = devm_reset_control_get(dev, "tcphy_rst");
+	if (IS_ERR(tcphy->phy_rst)) {
+		dev_err(dev, "no phy_rst reset control found\n");
+		return PTR_ERR(tcphy->phy_rst);
+	}
+
+	tcphy->pipe_rst = devm_reset_control_get(dev, "tcphy_pipe_rst");
+	if (IS_ERR(tcphy->pipe_rst)) {
+		dev_err(dev, "no pipe_rst reset control found\n");
+		return PTR_ERR(tcphy->pipe_rst);
+	}
+
+	tcphy->uphy_rst = devm_reset_control_get(dev, "uphy_tcphy_rst");
+	if (IS_ERR(tcphy->uphy_rst)) {
+		dev_err(dev, "no uphy_rst reset control found\n");
+		return PTR_ERR(tcphy->uphy_rst);
+	}
+
+	tcphy_parse_reg(tcphy, dev);
+	tcphy->mode = MODE_DISCONNECT;
+
+	tcphy->phy = devm_phy_create(dev, NULL, NULL);
+
+	phy_set_drvdata(tcphy->phy, tcphy);
+
+	phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+
+	/* register notifier for PD event */
+	ATOMIC_INIT_NOTIFIER_HEAD(&tcphy->notifier);
+	tcphy->event_nb.notifier_call = tcphy_pd_event;
+	INIT_DELAYED_WORK(&tcphy->event_wq, tcphy_event_wq);
+	tcphy_register_notifier(tcphy->phy, &tcphy->event_nb);
+
+	return PTR_ERR_OR_ZERO(phy_provider);
+}
+
+static int rockchip_typec_phy_remove(struct platform_device *pdev)
+{
+	return 0;
+}
+
+static const struct of_device_id rockchip_typec_phy_dt_ids[] = {
+	{ .compatible = "rockchip,rk3399-typec-phy", },
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids);
+
+static struct platform_driver rockchip_typec_phy_driver = {
+	.probe		= rockchip_typec_phy_probe,
+	.remove		= rockchip_typec_phy_remove,
+	.driver		= {
+		.name	= "rockchip-typec-phy",
+		.of_match_table = rockchip_typec_phy_dt_ids,
+	},
+};
+
+module_platform_driver(rockchip_typec_phy_driver);
+
+MODULE_AUTHOR("Kever Yang<kever.yang at rock-chips.com>");
+MODULE_AUTHOR("Chris Zhong<zyw at rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip USB TYPE-C PHY driver");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/phy/phy-rockchip-typec.h b/include/linux/phy/phy-rockchip-typec.h
new file mode 100644
index 0000000..b055297
--- /dev/null
+++ b/include/linux/phy/phy-rockchip-typec.h
@@ -0,0 +1,72 @@
+#ifndef PHY_ROCKCHIP_TYPEC_H_
+#define PHY_ROCKCHIP_TYPEC_H_
+#include <linux/notifier.h>
+
+struct tcphy_grf_reg {
+	u32 usb3phy_con0;
+	u32 usb3phy_con0_shift;
+	u32 usb3phy_con0_mask;
+	u32 usb3phy_con1;
+	u32 usb3phy_con1_shift;
+	u32 usb3phy_con1_mask;
+	u32 usb3phy_con2;
+	u32 usb3phy_con2_shift;
+	u32 usb3phy_con2_mask;
+	u32 usb3phy_status0;
+	u32 usb3phy_status0_shift;
+	u32 usb3phy_status0_mask;
+	u32 usb3phy_status1;
+	u32 usb3phy_status1_shift;
+	u32 usb3phy_status1_mask;
+};
+
+enum phy_num {
+	TYPEC_PHY0,
+	TYPEC_PHY1,
+};
+
+#define	PIN_MAP_A	BIT(0)
+#define	PIN_MAP_B	BIT(1)
+#define	PIN_MAP_C	BIT(2)
+#define	PIN_MAP_D	BIT(3)
+#define	PIN_MAP_E	BIT(4)
+#define	PIN_MAP_F	BIT(5)
+
+#define SET_PIN_MAP(x)	(((x) & 0xff) << 24)
+#define SET_DP(x)	(((x) & 0xff) << 16)
+#define SET_DFP(x)	(((x) & 0xff) << 8)
+#define SET_FLIP(x)	((x) & 0xff)
+#define GET_PIN_MAP(x)	(((x) >> 24) & 0xff)
+#define GET_DP(x)	(((x) >> 16) & 0xff)
+#define GET_DFP(x)	(((x) >> 8) & 0xff)
+#define GET_FLIP(x)	((x) & 0xff)
+
+struct rockchip_typec_phy {
+	struct device *dev;
+	void __iomem *base;
+	struct phy	*phy;
+	struct regmap *grf_regs;
+	struct tcphy_grf_reg exregs;
+	struct clk	*clk_core;
+	struct clk	*clk_ref;
+	struct reset_control *phy_rst;
+	struct reset_control *pipe_rst;
+	struct reset_control *uphy_rst;
+
+	/* to receive notifier from PD */
+	struct atomic_notifier_head     notifier;
+	struct notifier_block	event_nb;
+	struct delayed_work	event_wq;
+
+	bool flip;
+	unsigned int mode;
+	enum phy_num num;
+	int map;
+};
+
+int tcphy_register_notifier(struct phy *_phy, struct notifier_block *nb);
+void tcphy_unregister_notifier(struct phy *_phy, struct notifier_block *nb);
+struct rockchip_typec_phy *get_tcphy(void);
+void tcphy_notifier_call_chain(struct rockchip_typec_phy *x,
+			       unsigned long val, void *v);
+#endif
-- 
2.6.3



From zyw at rock-chips.com  Fri May 27 03:45:38 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 18:45:38 +0800
Subject: [RESEND PATCH 2/6] Documentation: bindings: add dt doc for Rockchip
 USB Type-C PHY
In-Reply-To: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
References: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464345942-4795-3-git-send-email-zyw@rock-chips.com>

This patch adds a binding that describes the Rockchip USB Type-C PHY
for rk3399.

Signed-off-by: Chris Zhong <zyw at rock-chips.com>
---

 .../devicetree/bindings/phy/phy-rockchip-typec.txt | 55 ++++++++++++++++++++++
 1 file changed, 55 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt

diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
new file mode 100644
index 0000000..402f667
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
@@ -0,0 +1,55 @@
+ROCKCHIP type-c PHY
+
+Required properties:
+ - compatible: should be "rockchip,rk3399-typec-phy"
+ - reg : Address and length of the usb phy control register set
+ - rockchip,grf : phandle to the syscon managing the "general
+   register files"
+ - clocks : phandle + clock specifier for the phy clocks
+ - clock-names: string, clock name, must be "tcpdcore", "tcpdphy_ref";
+ - resets : a list of phandle + reset specifier pairs
+ - reset-names : string reset name, must be:
+		 "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst"
+ - #phy-cells: Must be 0.  See ./phy-bindings.txt for details.
+ - rockchip,usb3phy*: phy registers embed in grf
+
+Example:
+	tcphy0: phy at ff7c0000 {
+		compatible = "rockchip,rk3399-typec-phy";
+		reg = <0x0 0xff7c0000 0x0 0x40000>;
+		#phy-cells = <0>;
+		rockchip,grf = <&grf>;
+		clocks = <&cru SCLK_UPHY0_TCPDCORE>,
+			 <&cru SCLK_UPHY0_TCPDPHY_REF>;
+		clock-names = "tcpdcore", "tcpdphy_ref";
+		resets = <&cru SRST_UPHY0>,
+			 <&cru SRST_UPHY0_PIPE_L00>,
+			 <&cru SRST_P_UPHY0_TCPHY>;
+		reset-names = "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst";
+		rockchip,usb3phy_con0 = <0x0e580 0 16>;
+		rockchip,usb3phy_con1 = <0x0e584 0 16>;
+		rockchip,usb3phy_con2 = <0x0e588 0 16>;
+		rockchip,usb3phy_status0 = <0x0e5c0 0 13>;
+		rockchip,usb3phy_status1 = <0x0e5c4 0 12>;
+		status = "disabled";
+	};
+
+	tcphy1: phy at ff800000 {
+		compatible = "rockchip,rk3399-typec-phy";
+		reg = <0x0 0xff800000 0x0 0x40000>;
+		#phy-cells = <0>;
+		rockchip,grf = <&grf>;
+		clocks = <&cru SCLK_UPHY1_TCPDCORE>,
+			 <&cru SCLK_UPHY1_TCPDPHY_REF>;
+		clock-names = "tcpdcore", "tcpdphy_ref";
+		resets = <&cru SRST_UPHY1>,
+		         <&cru SRST_UPHY1_PIPE_L00>,
+			 <&cru SRST_P_UPHY1_TCPHY>;
+		reset-names = "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst";
+		rockchip,usb3phy_con0 = <0x0e58c 0 16>;
+		rockchip,usb3phy_con1 = <0x0e590 0 16>;
+		rockchip,usb3phy_con2 = <0x0e594 0 16>;
+		rockchip,usb3phy_status0 = <0x0e5c0 16 13>;
+		rockchip,usb3phy_status1 = <0x0e5c4 16 12>;
+		status = "disabled";
+	};
-- 
2.6.3



From zyw at rock-chips.com  Fri May 27 03:45:40 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 18:45:40 +0800
Subject: [RESEND PATCH 4/6] Documentation: bindings: add dt documentation for
 cdn DP controller
In-Reply-To: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
References: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464345942-4795-5-git-send-email-zyw@rock-chips.com>

This patch adds a binding that describes the cdn DP controller for
rk3399.

Signed-off-by: Chris Zhong <zyw at rock-chips.com>
---

 .../bindings/display/rockchip/cdn-dp-rockchip.txt  | 57 ++++++++++++++++++++++
 1 file changed, 57 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt

diff --git a/Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt b/Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt
new file mode 100644
index 0000000..60795c2
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/rockchip/cdn-dp-rockchip.txt
@@ -0,0 +1,57 @@
+Rockchip RK3399 specific extensions to the cdn Display Port
+================================
+
+Required properties:
+- compatible: "rockchip,cdn-dp"
+
+- reg: physical base address of the controller and length
+
+- clocks: from common clock binding: handle to dp clock.
+
+- clock-names: from common clock binding:
+	       Required elements: "core_clk" "pclk" "spdif"
+
+- rockchip,grf: this soc should set GRF regs, so need get grf here.
+
+- ports: contain a port nodes with endpoint definitions as defined in
+	 Documentation/devicetree/bindings/media/video-interfaces.txt.
+	 contained 2 endpoints, connecting to the output of vop.
+
+- phys: from general PHY binding: the phandle for the PHY device.
+
+-------------------------------------------------------------------------------
+
+Example:
+	cdn_dp: dp at fec00000 {
+		compatible = "rockchip,cdn-dp";
+		reg = <0x0 0xfec00000 0x0 0x100000>;
+		interrupts = <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+		clocks = <&cru SCLK_DP_CORE>, <&cru PCLK_DP_CTRL>,
+			 <&cru SCLK_SPDIF_REC_DPTX>;
+		clock-names = "core_clk", "pclk", "spdif";
+		phys = <&tcphy0>;
+		rockchip,grf = <&grf>;
+		#address-cells = <1>;
+		#size-cells = <0>;
+		status = "disabled";
+
+		ports {
+			#address-cells = <1>;
+			#size-cells = <0>;
+			reg = <1>;
+
+			dp_in: port {
+				#address-cells = <1>;
+				#size-cells = <0>;
+				dp_in_vopb: endpoint at 0 {
+					reg = <0>;
+					remote-endpoint = <&vopb_out_dp>;
+				};
+
+				dp_in_vopl: endpoint at 1 {
+					reg = <1>;
+					remote-endpoint = <&vopl_out_dp>;
+				};
+			};
+		};
+	};
-- 
2.6.3



From zyw at rock-chips.com  Fri May 27 03:45:39 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 18:45:39 +0800
Subject: [RESEND PATCH 3/6] drm/rockchip: vop: add cdn DP support for rk3399
In-Reply-To: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
References: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464345942-4795-4-git-send-email-zyw@rock-chips.com>

Add support for cdn DP controller which is embedded in the rk3399
SoCs. The DP is compliant with DisplayPort Specification,
Version 1.3, This IP is compatible with the rockchip type-c PHY IP.
There is a uCPU in DP controller, it need a firmware to work,
please put the firmware file to /lib/firmware/cdn/dptx.bin. The
uCPU in charge of aux communication and link training, the host use
mailbox to communicate with the ucpu.
The dclk pin_pol of vop must not be invert for DP.

Signed-off-by: Chris Zhong <zyw at rock-chips.com>
---

 drivers/gpu/drm/rockchip/Kconfig            |   9 +
 drivers/gpu/drm/rockchip/Makefile           |   1 +
 drivers/gpu/drm/rockchip/cdn-dp-core.c      | 620 +++++++++++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-core.h      |  95 ++++
 drivers/gpu/drm/rockchip/cdn-dp-reg.c       | 730 ++++++++++++++++++++++++++++
 drivers/gpu/drm/rockchip/cdn-dp-reg.h       | 404 +++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c |   9 +-
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h |   2 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c |   2 +
 include/sound/cdn-dp-audio.h                |  51 ++
 10 files changed, 1922 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-core.h
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.c
 create mode 100644 drivers/gpu/drm/rockchip/cdn-dp-reg.h
 create mode 100644 include/sound/cdn-dp-audio.h

diff --git a/drivers/gpu/drm/rockchip/Kconfig b/drivers/gpu/drm/rockchip/Kconfig
index d30bdc3..20da9a8 100644
--- a/drivers/gpu/drm/rockchip/Kconfig
+++ b/drivers/gpu/drm/rockchip/Kconfig
@@ -25,6 +25,15 @@ config ROCKCHIP_ANALOGIX_DP
 	  for the Analogix Core DP driver. If you want to enable DP
 	  on RK3288 based SoC, you should selet this option.
 
+config ROCKCHIP_CDN_DP
+        tristate "Rockchip cdn DP"
+        depends on DRM_ROCKCHIP
+        help
+	  This selects support for Rockchip SoC specific extensions
+	  for the cdn Dp driver. If you want to enable Dp on
+	  RK3399 based SoC, you should selet this
+	  option.
+
 config ROCKCHIP_DW_HDMI
         tristate "Rockchip specific extensions for Synopsys DW HDMI"
         depends on DRM_ROCKCHIP
diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..abdecd5 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -7,6 +7,7 @@ rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
+obj-$(CONFIG_ROCKCHIP_CDN_DP) += cdn-dp-core.o cdn-dp-reg.o
 obj-$(CONFIG_ROCKCHIP_DW_HDMI) += dw_hdmi-rockchip.o
 obj-$(CONFIG_ROCKCHIP_DW_MIPI_DSI) += dw-mipi-dsi.o
 obj-$(CONFIG_ROCKCHIP_INNO_HDMI) += inno_hdmi.o
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.c b/drivers/gpu/drm/rockchip/cdn-dp-core.c
new file mode 100644
index 0000000..fdf99f5
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.c
@@ -0,0 +1,620 @@
+/*
+ * cdn dp controller core driver
+ *
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <drm/drmP.h>
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_edid.h>
+#include <drm/drm_of.h>
+
+#include <linux/component.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+#include <linux/mfd/syscon.h>
+#include <linux/phy/phy.h>
+#include <linux/phy/phy-rockchip-typec.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+#include <video/of_videomode.h>
+#include <video/videomode.h>
+
+#include <sound/cdn-dp-audio.h>
+
+#include "rockchip_drm_vop.h"
+#include "cdn-dp-reg.h"
+#include "cdn-dp-core.h"
+
+#define connector_to_dp(c) \
+		container_of(c, struct cdn_dp_device, connector)
+
+#define encoder_to_dp(c) \
+		container_of(c, struct cdn_dp_device, encoder)
+
+/* dp grf register offset */
+#define DP_VOP_SEL		0x6224
+#define DP_SEL_VOP_LIT		BIT(12)
+
+static int cdn_dp_clk_enable(struct cdn_dp_device *dp)
+{
+	int ret = 0;
+	int clk_rate = 200000000;
+
+	ret = clk_prepare_enable(dp->pclk);
+	if (ret < 0) {
+		dev_err(dp->dev, "cannot enable dp pclk %d\n", ret);
+		goto err_pclk;
+	}
+
+	ret = clk_prepare_enable(dp->core_clk);
+	if (ret < 0) {
+		dev_err(dp->dev, "cannot enable core_clk %d\n", ret);
+		goto err_core_clk;
+	}
+
+	ret = clk_set_rate(dp->core_clk, clk_rate);
+	if (ret < 0) {
+		dev_err(dp->dev, "cannot set dp core clk to %d %d\n",
+			clk_rate, ret);
+		goto err_set_rate;
+	}
+
+	/* notice fw the clk freq value */
+	cdn_dp_set_fw_clk(dp, clk_rate);
+
+	return 0;
+
+err_set_rate:
+	clk_disable_unprepare(dp->core_clk);
+err_core_clk:
+	clk_disable_unprepare(dp->pclk);
+err_pclk:
+	return ret;
+}
+
+static enum drm_connector_status
+cdn_dp_connector_detect(struct drm_connector *connector, bool force)
+{
+	struct cdn_dp_device *dp = connector_to_dp(connector);
+	int ret;
+
+	if (!dp->fw_loaded)
+		return connector_status_unknown;
+
+	ret = cdn_dp_get_hpd_status(dp);
+	if (ret < 0)
+		return connector_status_unknown;
+
+	dp->plugged = ret;
+
+	return ret ? connector_status_connected : connector_status_disconnected;
+}
+
+static void cdn_dp_connector_destroy(struct drm_connector *connector)
+{
+	drm_connector_unregister(connector);
+	drm_connector_cleanup(connector);
+}
+
+static struct drm_connector_funcs cdn_dp_atomic_connector_funcs = {
+	.dpms = drm_atomic_helper_connector_dpms,
+	.detect = cdn_dp_connector_detect,
+	.destroy = cdn_dp_connector_destroy,
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int cdn_dp_connector_get_modes(struct drm_connector *connector)
+{
+	struct cdn_dp_device *dp = connector_to_dp(connector);
+	struct edid *edid;
+	int ret;
+
+	if (!dp->fw_loaded)
+		return 0;
+
+	ret = cdn_dp_set_host_cap(dp);
+	if (ret) {
+		dev_err(dp->dev, "set host capabilities failed:%d\n", ret);
+		return ret;
+	}
+
+	edid = drm_do_get_edid(connector, cdn_dp_get_edid_block, dp);
+	if (edid) {
+		dev_dbg(dp->dev, "got edid: width[%d] x height[%d]\n",
+			edid->width_cm, edid->height_cm);
+
+		dp->sink_has_audio = drm_detect_monitor_audio(edid);
+		drm_mode_connector_update_edid_property(connector, edid);
+		drm_add_edid_modes(connector, edid);
+		/* Store the ELD */
+		drm_edid_to_eld(connector, edid);
+		kfree(edid);
+	} else {
+		dev_dbg(dp->dev, "failed to get edid\n");
+	}
+
+	/*
+	 * put the training process here, since the mode_valid need the
+	 * training result to check if the resolution is support.
+	 */
+	ret = cdn_dp_training_start(dp);
+	if (ret) {
+		dev_err(dp->dev, "hw lt err:%d\n", ret);
+		return ret;
+	}
+
+	ret = cdn_dp_get_lt_status(dp);
+	if (ret) {
+		dev_err(dp->dev, "hw lt get status err:%d\n", ret);
+		return ret;
+	}
+
+	dev_dbg(dp->dev, "rate:%d, lanes:%d\n",
+		dp->link.rate, dp->link.num_lanes);
+	return 0;
+}
+
+static struct drm_encoder *
+	cdn_dp_connector_best_encoder(struct drm_connector *connector)
+{
+	struct cdn_dp_device *dp = connector_to_dp(connector);
+
+	return &dp->encoder;
+}
+
+static int cdn_dp_connector_mode_valid(struct drm_connector *connector,
+				       struct drm_display_mode *mode)
+{
+	struct cdn_dp_device *dp = connector_to_dp(connector);
+	struct drm_display_info *display_info = &dp->connector.display_info;
+	long requested = mode->clock * display_info->bpc * 3 / 1000;
+	long actual, rate;
+
+	rate = drm_dp_bw_code_to_link_rate(dp->link.rate);
+	actual = rate * dp->link.num_lanes / 100;
+
+	/* efficiency is about 0.8 */
+	actual = actual * 8 / 10;
+
+	if (requested > actual) {
+		dev_dbg(dp->dev, "requested=%ld, actual=%ld, clock=%d, bpc= %d\n",
+			requested, actual, mode->clock, display_info->bpc);
+		return MODE_H_ILLEGAL;
+	}
+
+	return MODE_OK;
+}
+
+static struct drm_connector_helper_funcs cdn_dp_connector_helper_funcs = {
+	.get_modes = cdn_dp_connector_get_modes,
+	.best_encoder = cdn_dp_connector_best_encoder,
+	.mode_valid = cdn_dp_connector_mode_valid,
+};
+
+static int cdn_dp_commit(struct drm_encoder *encoder)
+{
+	struct cdn_dp_device *dp = encoder_to_dp(encoder);
+	int ret;
+
+	cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
+
+	ret = cdn_dp_config_video(dp);
+	if (ret) {
+		dev_err(dp->dev, "unable to config video\n");
+		return ret;
+	}
+
+	cdn_dp_set_video_status(dp, CONTROL_VIDEO_VALID);
+	dp->dpms_mode = DRM_MODE_DPMS_ON;
+
+	return ret;
+}
+
+static void cdn_dp_encoder_mode_set(struct drm_encoder *encoder,
+				    struct drm_display_mode *mode,
+				    struct drm_display_mode *adjusted)
+{
+	struct cdn_dp_device *dp = encoder_to_dp(encoder);
+	struct drm_display_info *display_info = &dp->connector.display_info;
+	struct rockchip_crtc_state *state;
+	struct video_info *video = &dp->video_info;
+	int ret, val;
+
+	switch (display_info->bpc) {
+	case 16:
+	case 12:
+	case 10:
+		video->color_depth = 10;
+		break;
+	case 6:
+		video->color_depth = 6;
+		break;
+	default:
+		video->color_depth = 8;
+		break;
+	}
+
+	video->color_fmt = PXL_RGB;
+
+	video->v_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NVSYNC);
+	video->h_sync_polarity = !!(mode->flags & DRM_MODE_FLAG_NHSYNC);
+
+	ret = drm_of_encoder_active_endpoint_id(dp->dev->of_node, encoder);
+	if (ret < 0)
+		return;
+
+	state = to_rockchip_crtc_state(encoder->crtc->state);
+	if (ret) {
+		val = DP_SEL_VOP_LIT | (DP_SEL_VOP_LIT << 16);
+		state->output_mode = ROCKCHIP_OUT_MODE_P888;
+	} else {
+		val = DP_SEL_VOP_LIT << 16;
+		state->output_mode = ROCKCHIP_OUT_MODE_AAAA;
+	}
+	ret = regmap_write(dp->grf, DP_VOP_SEL, val);
+	if (ret != 0)
+		dev_err(dp->dev, "Could not write to GRF: %d\n", ret);
+
+	memcpy(&dp->mode, adjusted, sizeof(*mode));
+}
+
+static void cdn_dp_encoder_enable(struct drm_encoder *encoder)
+{
+	struct cdn_dp_device *dp = encoder_to_dp(encoder);
+
+	if (dp->dpms_mode == DRM_MODE_DPMS_ON)
+		return;
+
+	cdn_dp_commit(encoder);
+}
+
+static void cdn_dp_encoder_disable(struct drm_encoder *encoder)
+{
+	struct cdn_dp_device *dp = encoder_to_dp(encoder);
+
+	if (dp->dpms_mode != DRM_MODE_DPMS_ON)
+		return;
+
+	cdn_dp_set_video_status(dp, CONTROL_VIDEO_IDLE);
+
+	dp->dpms_mode = DRM_MODE_DPMS_OFF;
+}
+
+static int
+cdn_dp_encoder_atomic_check(struct drm_encoder *encoder,
+			    struct drm_crtc_state *crtc_state,
+			    struct drm_connector_state *conn_state)
+{
+	struct rockchip_crtc_state *s = to_rockchip_crtc_state(crtc_state);
+
+	s->output_mode = ROCKCHIP_OUT_MODE_AAAA;
+	s->output_type = DRM_MODE_CONNECTOR_DisplayPort;
+
+	return 0;
+}
+
+static struct drm_encoder_helper_funcs cdn_dp_encoder_helper_funcs = {
+	.mode_set = cdn_dp_encoder_mode_set,
+	.enable = cdn_dp_encoder_enable,
+	.disable = cdn_dp_encoder_disable,
+	.atomic_check = cdn_dp_encoder_atomic_check,
+};
+
+static struct drm_encoder_funcs cdn_dp_encoder_funcs = {
+	.destroy = drm_encoder_cleanup,
+};
+
+int cdn_dp_firmware_init(struct cdn_dp_device *dp)
+{
+	int ret;
+	const u32 *iram_data, *dram_data;
+	const struct firmware *fw;
+	const struct cdn_firmware_header *hdr;
+
+	if (dp->fw_loaded)
+		return 0;
+
+	ret = request_firmware(&fw, "cdn/dptx.bin", dp->dev);
+	if (ret < 0) {
+		dev_err(dp->dev, "failed to request firmware %d\n", ret);
+		return ret;
+	}
+
+	hdr = (struct cdn_firmware_header *)fw->data;
+	if (fw->size != le32_to_cpu(hdr->size_bytes))
+		return -EINVAL;
+
+	ret = cdn_dp_clk_enable(dp);
+	if (ret < 0) {
+		dev_err(dp->dev, "cannot enable dp clk %d\n", ret);
+		return ret;
+	}
+
+	dp_clock_reset_seq(dp);
+
+	iram_data = (const u32 *)(fw->data + hdr->header_size);
+	dram_data = (const u32 *)(fw->data + hdr->header_size + hdr->iram_size);
+
+	ret = cdn_dp_load_firmware(dp,
+				   iram_data, hdr->iram_size,
+				   dram_data, hdr->dram_size);
+
+	ret = cdn_dp_active(dp, true);
+	if (ret) {
+		dev_err(dp->dev, "active ucpu failed: %d\n", ret);
+		return ret;
+	}
+
+	cdn_dp_event_config(dp);
+
+	return 0;
+}
+
+static int cdn_dp_init(struct cdn_dp_device *dp)
+{
+	struct device *dev = dp->dev;
+	struct device_node *np = dev->of_node;
+	struct platform_device *pdev = to_platform_device(dev);
+	struct resource *res;
+
+	dp->grf = syscon_regmap_lookup_by_phandle(np, "rockchip,grf");
+	if (IS_ERR(dp->grf)) {
+		dev_err(dev, "cdn-dp needs rockchip,grf property\n");
+		return PTR_ERR(dp->grf);
+	}
+
+	dp->irq = platform_get_irq(pdev, 0);
+	if (dp->irq < 0) {
+		dev_err(dev, "cdn-dp can not get irq\n");
+		return dp->irq;
+	}
+
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	dp->regs = devm_ioremap_resource(dev, res);
+	if (IS_ERR(dp->regs)) {
+		dev_err(dev, "ioremap reg failed\n");
+		return PTR_ERR(dp->regs);
+	}
+
+	dp->core_clk = devm_clk_get(dev, "core_clk");
+	if (IS_ERR(dp->core_clk)) {
+		dev_err(dev, "cannot get core_clk_dp\n");
+		return PTR_ERR(dp->core_clk);
+	}
+
+	dp->pclk = devm_clk_get(dev, "pclk");
+	if (IS_ERR(dp->pclk)) {
+		dev_err(dev, "cannot get pclk\n");
+		return PTR_ERR(dp->pclk);
+	}
+
+	dp->spdif_clk = devm_clk_get(dev, "spdif");
+	if (IS_ERR(dp->spdif_clk)) {
+		dev_err(dev, "cannot get spdif_clk\n");
+		return PTR_ERR(dp->spdif_clk);
+	}
+
+	dp->dpms_mode = DRM_MODE_DPMS_OFF;
+
+	dev_set_name(dp->dev, "cdn-dp");
+
+	return 0;
+}
+
+static const struct cdn_dp_audio_ops dp_audio_ops = {
+	.audio_startup = cdn_dp_audio_start,
+	.audio_shutdown = cdn_dp_audio_stop,
+	.audio_start = cdn_dp_audio_start,
+	.audio_stop = cdn_dp_audio_stop,
+	.audio_config = cdn_dp_audio_config_set,
+};
+
+static int cdn_dp_pd_event(struct notifier_block *nb,
+			   unsigned long event, void *priv)
+{
+	struct cdn_dp_device *dp;
+	u8 map, is_dp;
+	int value = *(int *)priv;
+
+	dp = container_of(nb, struct cdn_dp_device, event_nb);
+	if (IS_ERR_OR_NULL(dp)) {
+		pr_err("initialization issue");
+		return -1;
+	}
+
+	is_dp = GET_DP(value);
+
+	if (!is_dp)
+		return 0;
+
+	dp->flip = GET_FLIP(value);
+	map = GET_PIN_MAP(value);
+	if (map & (PIN_MAP_B | PIN_MAP_D | PIN_MAP_F))
+		dp->cap_lanes = 2;
+	else
+		dp->cap_lanes = 4;
+
+	schedule_delayed_work_on(0, &dp->event_wq, 100);
+
+	return 0;
+}
+
+static void cdn_dp_pd_event_wq(struct work_struct *work)
+{
+	struct cdn_dp_device *dp;
+
+	dp = container_of(work, struct cdn_dp_device, event_wq.work);
+	if (IS_ERR_OR_NULL(dp)) {
+		pr_err("initialization issue");
+		return;
+	}
+
+	if (cdn_dp_firmware_init(dp))
+		return;
+
+	if ((cdn_dp_get_event(dp) & DPTX_HPD_EVENT) && (dp->drm_dev))
+		drm_helper_hpd_irq_event(dp->drm_dev);
+}
+
+static int cdn_dp_bind(struct device *dev, struct device *master,
+		       void *data)
+{
+	struct cdn_dp_audio_pdata audio_pdata;
+	struct cdn_dp_device *dp = dev_get_drvdata(dev);
+	struct device_node *np = dev->of_node;
+	struct drm_encoder *encoder;
+	struct drm_connector *connector;
+	struct drm_device *drm_dev = data;
+	struct phy *phy = devm_of_phy_get_by_index(dev, np, 0);
+	int ret;
+
+	if (IS_ERR(phy))
+		return -EPROBE_DEFER;
+
+	dp->phy = phy;
+
+	ret = cdn_dp_init(dp);
+	if (ret < 0)
+		return ret;
+
+	dp->drm_dev = drm_dev;
+
+	encoder = &dp->encoder;
+
+	encoder->possible_crtcs = drm_of_find_possible_crtcs(drm_dev,
+							     dev->of_node);
+	DRM_DEBUG_KMS("possible_crtcs = 0x%x\n", encoder->possible_crtcs);
+
+	ret = drm_encoder_init(drm_dev, encoder, &cdn_dp_encoder_funcs,
+			       DRM_MODE_ENCODER_TMDS, NULL);
+	if (ret) {
+		DRM_ERROR("failed to initialize encoder with drm\n");
+		return ret;
+	}
+
+	drm_encoder_helper_add(encoder, &cdn_dp_encoder_helper_funcs);
+
+	connector = &dp->connector;
+	connector->polled = DRM_CONNECTOR_POLL_HPD;
+	connector->dpms = DRM_MODE_DPMS_OFF;
+
+	ret = drm_connector_init(drm_dev, connector,
+				 &cdn_dp_atomic_connector_funcs,
+				 DRM_MODE_CONNECTOR_DisplayPort);
+	if (ret) {
+		DRM_ERROR("failed to initialize connector with drm\n");
+		goto err_free_encoder;
+	}
+
+	drm_connector_helper_add(connector, &cdn_dp_connector_helper_funcs);
+
+	ret = drm_mode_connector_attach_encoder(connector, encoder);
+	if (ret) {
+		DRM_ERROR("failed to attach connector and encoder\n");
+		goto err_free_connector;
+	}
+
+	audio_pdata.dev = dev,
+	audio_pdata.ops = &dp_audio_ops,
+	audio_pdata.data = dp;
+
+	dp->audio_pdev = platform_device_register_data(
+		dev, "cdn-dp-audio", PLATFORM_DEVID_NONE,
+		&audio_pdata, sizeof(audio_pdata));
+
+	if (IS_ERR(dp->audio_pdev))
+		return PTR_ERR(dp->audio_pdev);
+
+	dp->event_nb.notifier_call = cdn_dp_pd_event;
+	INIT_DELAYED_WORK(&dp->event_wq, cdn_dp_pd_event_wq);
+	tcphy_register_notifier(phy, &dp->event_nb);
+
+	return 0;
+
+err_free_connector:
+	drm_connector_cleanup(connector);
+err_free_encoder:
+	drm_encoder_cleanup(encoder);
+	return ret;
+}
+
+static void cdn_dp_unbind(struct device *dev, struct device *master, void *data)
+{
+	struct cdn_dp_device *dp = dev_get_drvdata(dev);
+	struct drm_encoder *encoder = &dp->encoder;
+
+	platform_device_unregister(dp->audio_pdev);
+	cdn_dp_encoder_disable(encoder);
+	encoder->funcs->destroy(encoder);
+	drm_connector_unregister(&dp->connector);
+	drm_connector_cleanup(&dp->connector);
+	drm_encoder_cleanup(encoder);
+	tcphy_unregister_notifier(dp->phy, &dp->event_nb);
+}
+
+static const struct component_ops cdn_dp_component_ops = {
+	.bind = cdn_dp_bind,
+	.unbind = cdn_dp_unbind,
+};
+
+static int cdn_dp_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct cdn_dp_device *dp;
+
+	dp = devm_kzalloc(dev, sizeof(*dp), GFP_KERNEL);
+	if (!dp)
+		return -ENOMEM;
+	dp->dev = dev;
+
+	platform_set_drvdata(pdev, dp);
+
+	return component_add(dev, &cdn_dp_component_ops);
+}
+
+static int cdn_dp_remove(struct platform_device *pdev)
+{
+	component_del(&pdev->dev, &cdn_dp_component_ops);
+
+	return 0;
+}
+
+static const struct of_device_id cdn_dp_dt_ids[] = {
+	{.compatible = "rockchip,cdn-dp",},
+	{}
+};
+
+MODULE_DEVICE_TABLE(of, cdn_dp_dt_ids);
+
+static struct platform_driver cdn_dp_driver = {
+	.probe = cdn_dp_probe,
+	.remove = cdn_dp_remove,
+	.driver = {
+		   .name = "cdn-dp",
+		   .owner = THIS_MODULE,
+		   .of_match_table = of_match_ptr(cdn_dp_dt_ids),
+	},
+};
+
+module_platform_driver(cdn_dp_driver);
+
+MODULE_AUTHOR("Chris Zhong <zyw at rock-chips.com>");
+MODULE_DESCRIPTION("cdn DP Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-core.h b/drivers/gpu/drm/rockchip/cdn-dp-core.h
new file mode 100644
index 0000000..99c0123
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/cdn-dp-core.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _ROCKCHIP_EDP_CORE_H
+#define _ROCKCHIP_EDP_CORE_H
+
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_panel.h>
+#include "rockchip_drm_drv.h"
+#include "cdn-dp-reg.h"
+
+struct video_info {
+	bool h_sync_polarity;
+	bool v_sync_polarity;
+	bool interlaced;
+	int color_depth;
+	enum VIC_PXL_ENCODING_FORMAT color_fmt;
+};
+
+struct cdn_firmware_header {
+	u32 size_bytes; /* size of the entire header+image(s) in bytes */
+	u32 header_size; /* size of just the header in bytes */
+	u32 iram_size; /* size of iram */
+	u32 dram_size; /* size of dram */
+};
+
+struct cdn_dp_device {
+	struct device *dev;
+	struct drm_device *drm_dev;
+	struct drm_connector connector;
+	struct drm_encoder encoder;
+	struct drm_display_mode mode;
+	struct delayed_work hotplug_work;
+	struct platform_device *audio_pdev;
+	bool plugged;
+
+	const struct firmware *fw;	/* cdn dp firmware */
+	unsigned int fw_version;	/* cdn fw version */
+	bool fw_loaded;
+	void __iomem *regs;
+	void __iomem *phy_regs;
+	struct regmap *grf;
+	unsigned int irq;
+	struct clk *core_clk;
+	struct clk *pclk;
+	struct clk *spdif_clk;
+	struct video_info video_info;
+	struct phy *phy;
+	struct notifier_block	event_nb;
+	struct delayed_work	event_wq;
+
+	int cap_lanes;
+	bool flip;
+
+	int dpms_mode;
+	struct drm_dp_link link;
+	bool sink_has_audio;
+};
+
+void dp_clock_reset_seq(struct cdn_dp_device *dp);
+
+void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, int clk);
+int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem,
+			 u32 i_size, const u32 *d_mem, u32 d_size);
+int cdn_dp_active(struct cdn_dp_device *dp, u8 enable);
+int cdn_dp_set_host_cap(struct cdn_dp_device *dp);
+int cdn_dp_event_config(struct cdn_dp_device *dp);
+int cdn_dp_get_event(struct cdn_dp_device *dp);
+int cdn_dp_get_hpd_status(struct cdn_dp_device *dp);
+int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value);
+int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr);
+int cdn_dp_get_edid_block(void *dp, u8 *edid,
+			  unsigned int block, size_t length);
+int cdn_dp_training_start(struct cdn_dp_device *dp);
+int cdn_dp_get_lt_status(struct cdn_dp_device *dp);
+int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active);
+int cdn_dp_config_video(struct cdn_dp_device *dp);
+int cdn_dp_audio_start(void *dp_dev, struct audio_info *audio);
+int cdn_dp_audio_stop(void *dp_dev, struct audio_info *audio);
+int cdn_dp_audio_config_set(void *dp_dev, struct audio_info *audio);
+
+#endif  /* _ROCKCHIP_EDP_CORE_H */
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.c b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
new file mode 100644
index 0000000..d6c9bcb
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.c
@@ -0,0 +1,730 @@
+/*
+ * cdn dp controller register driver
+ *
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/device.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/reset.h>
+
+#include <sound/cdn-dp-audio.h>
+
+#include "cdn-dp-core.h"
+#include "cdn-dp-reg.h"
+
+#define FW_ALIVE_TIMEOUT_US		1000000
+#define MAILBOX_TIMEOUT_US		5000000
+
+/* the max size of read buff is 134 */
+static u8 rx_buff[134];
+
+void cdn_dp_set_fw_clk(struct cdn_dp_device *dp, int clk)
+{
+	writel(clk / 1000000, dp->regs + SW_CLK_H);
+}
+
+void dp_clock_reset_seq(struct cdn_dp_device *dp)
+{
+	writel(0xfff, dp->regs + SOURCE_DPTX_CAR);
+	writel(0x7, dp->regs + SOURCE_PHY_CAR);
+	writel(0xf, dp->regs + SOURCE_PKT_CAR);
+	writel(0xff, dp->regs + SOURCE_AIF_CAR);
+	writel(0xf, dp->regs + SOURCE_CIPHER_CAR);
+	writel(0x3, dp->regs + SOURCE_CRYPTO_CAR);
+	writel(0, dp->regs + APB_INT_MASK);
+}
+
+static u8 cdn_dp_mailbox_read(struct cdn_dp_device *dp)
+{
+	int val, ret;
+
+	if (!dp->fw_loaded)
+		return 0;
+
+	ret = readx_poll_timeout(readl, dp->regs + MAILBOX_EMPTY_ADDR,
+				 val, !val, 1000, MAILBOX_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(dp->dev, "failed to wait mailbox response\n");
+		return 0;
+	}
+
+	return readl(dp->regs + MAILBOX0_RD_DATA) & 0xff;
+}
+
+static void cdp_dp_mailbox_write(struct cdn_dp_device *dp, u8 val)
+{
+	int ret, full;
+
+	if (!dp->fw_loaded)
+		return;
+
+	ret = readx_poll_timeout(readl, dp->regs + MAILBOX_FULL_ADDR,
+				 full, !full, 1000, MAILBOX_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(dp->dev, "mailbox is full\n");
+		return;
+	}
+
+	writel(val, dp->regs + MAILBOX0_WR_DATA);
+}
+
+/* return the size of message */
+int cdn_dp_mailbox_response(struct cdn_dp_device *dp, u8 module_id,
+			    u8 opcode, u8 **message)
+{
+	int size, i = 0;
+
+	memset(rx_buff, 0, 4);
+
+	while (i < sizeof(rx_buff)) {
+		if (i < sizeof(rx_buff))
+			rx_buff[i++] = cdn_dp_mailbox_read(dp);
+
+		size = ((rx_buff[2] << 8) | rx_buff[3]) + 4;
+		if (i >= size)
+			break;
+	}
+
+	if ((opcode != rx_buff[0]) || (module_id != rx_buff[1]))
+		return -EINVAL;
+
+	size = (rx_buff[2] << 8) | rx_buff[3];
+
+	*message = &rx_buff[4];
+
+	return size;
+}
+
+int cdn_dp_mailbox_send(struct cdn_dp_device *dp, u8 module_id, u8 opcode,
+			u16 size, u8 *message)
+{
+	cdp_dp_mailbox_write(dp, opcode);
+	cdp_dp_mailbox_write(dp, module_id);
+	cdp_dp_mailbox_write(dp, size >> 8);
+	cdp_dp_mailbox_write(dp, size & 0xff);
+
+	while (size--)
+		cdp_dp_mailbox_write(dp, *message++);
+
+	return 0;
+}
+
+int cdn_dp_load_firmware(struct cdn_dp_device *dp, const u32 *i_mem,
+			 u32 i_size, const u32 *d_mem, u32 d_size)
+{
+	int i, reg, ret;
+
+	/* reset ucpu before load firmware*/
+	writel(APB_IRAM_PATH | APB_DRAM_PATH | APB_XT_RESET,
+	       dp->regs + APB_CTRL);
+
+	for (i = 0; i < i_size; i += 4)
+		writel(*i_mem++, dp->regs + ADDR_IMEM + i);
+
+	for (i = 0; i < d_size; i += 4)
+		writel(*d_mem++, dp->regs + ADDR_DMEM + i);
+
+	/* un-reset ucpu */
+	writel(0, dp->regs + APB_CTRL);
+
+	/* check the keep alive register to make sure fw working */
+	ret = readx_poll_timeout(readl, dp->regs + KEEP_ALIVE,
+				 reg, reg, 2000, FW_ALIVE_TIMEOUT_US);
+	if (ret < 0) {
+		dev_err(dp->dev, "failed to loaded the FW reg = %x\n", reg);
+		return -EINVAL;
+	}
+
+	reg = readl(dp->regs + VER_L) & 0xff;
+	dp->fw_version = reg;
+	reg = readl(dp->regs + VER_H) & 0xff;
+	dp->fw_version |= reg << 8;
+	reg = readl(dp->regs + VER_LIB_L_ADDR) & 0xff;
+	dp->fw_version |= reg << 16;
+	reg = readl(dp->regs + VER_LIB_H_ADDR) & 0xff;
+	dp->fw_version |= reg << 24;
+
+	dp->fw_loaded = 1;
+
+	return 0;
+}
+
+int cdn_dp_reg_write(struct cdn_dp_device *dp, u16 addr, u32 val)
+{
+	u8 msg[6];
+
+	msg[0] = (addr >> 8) & 0xff;
+	msg[1] = addr & 0xff;
+	msg[2] = (val >> 24) & 0xff;
+	msg[3] = (val >> 16) & 0xff;
+	msg[4] = (val >> 8) & 0xff;
+	msg[5] = val & 0xff;
+	return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_REGISTER,
+				   ARRAY_SIZE(msg), msg);
+}
+
+int cdn_dp_reg_read(struct cdn_dp_device *dp, u16 addr)
+{
+	u8 msg[2], *reg = NULL;
+	u16 size;
+
+	msg[0] = (addr >> 8) & 0xff;
+	msg[1] = addr & 0xff;
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_REGISTER,
+			    ARRAY_SIZE(msg), msg);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_READ_REGISTER, &reg);
+	if (size != 6)
+		return -EINVAL;
+
+	if ((msg[0] == reg[0]) && (msg[1] == reg[1]))
+		return (reg[2] << 24) | (reg[3] << 16) | (reg[4] << 8) | reg[5];
+
+	return -EINVAL;
+}
+
+int cdn_dp_reg_write_bit(struct cdn_dp_device *dp, u16 addr, u8 start_bit,
+			 u8 bits_no, u32 val)
+{
+	u8 field[8];
+
+	field[0] = (addr >> 8) & 0xff;
+	field[1] = addr & 0xff;
+	field[2] = start_bit;
+	field[3] = bits_no;
+	field[4] = (val >> 24) & 0xff;
+	field[5] = (val >> 16) & 0xff;
+	field[6] = (val >> 8) & 0xff;
+	field[7] = val & 0xff;
+
+	return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_FIELD,
+			    sizeof(field), field);
+}
+
+int cdn_dp_dpcd_write(struct cdn_dp_device *dp, u32 addr, u8 value)
+{
+	u8 msg[6], *reg = NULL;
+	u16 size;
+
+	msg[0] = 0;
+	msg[1] = 1;
+	msg[2] = (addr >> 16) & 0xff;
+	msg[3] = (addr >> 8) & 0xff;
+	msg[4] = addr & 0xff;
+	msg[5] = value;
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_WRITE_DPCD,
+			    ARRAY_SIZE(msg), msg);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_WRITE_DPCD, &reg);
+	if (size != 5)
+		return -EINVAL;
+
+	if ((msg[2] == reg[2]) && (msg[3] == reg[3]) && (msg[4] == reg[4]))
+		return 0;
+
+	return -EINVAL;
+}
+
+int cdn_dp_dpcd_read(struct cdn_dp_device *dp, u32 addr)
+{
+	u8 msg[5], *reg = NULL;
+	u16 size;
+
+	msg[0] = 0;
+	msg[1] = 1;
+	msg[2] = (addr >> 16) & 0xff;
+	msg[3] = (addr >> 8) & 0xff;
+	msg[4] = addr & 0xff;
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_DPCD,
+			    ARRAY_SIZE(msg), msg);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_READ_DPCD, &reg);
+	if (size != 6)
+		return -EINVAL;
+
+	if ((msg[2] == reg[2]) && (msg[3] == reg[3]) && (msg[4] == reg[4]))
+		return reg[5];
+
+	return -EINVAL;
+}
+
+int cdn_dp_active(struct cdn_dp_device *dp, u8 enable)
+{
+	u8 active = enable ? 1 : 0;
+	u8 *resp = NULL;
+	int size;
+
+	/* set firmware status, 1: avtive; 0: standby */
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_GENERAL, GENERAL_MAIN_CONTROL,
+			    1, &active);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_GENERAL,
+				       GENERAL_MAIN_CONTROL, &resp);
+	if (size != 1)
+		return -EINVAL;
+
+	return *resp ? 0 : -EINVAL;
+}
+
+int cdn_dp_set_host_cap(struct cdn_dp_device *dp)
+{
+	u8 msg[8];
+
+	msg[0] = DP_LINK_BW_5_4;
+	msg[1] = dp->cap_lanes;
+	msg[2] = VOLTAGE_LEVEL_2;
+	msg[3] = PRE_EMPHASIS_LEVEL_3;
+	msg[4] = PRBS7 | D10_2 | TRAINING_PTN1 | TRAINING_PTN2;
+	msg[5] = FAST_LT_NOT_SUPPORT;
+	msg[6] = LANE_MAPPING_NORMAL;
+	msg[7] = ENHANCED;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX,
+			    DPTX_SET_HOST_CAPABILITIES,
+			    ARRAY_SIZE(msg), msg);
+
+	cdn_dp_reg_write(dp, DP_AUX_SWAP_INVERSION_CONTROL, AUX_HOST_INVERT);
+
+	return 0;
+}
+
+int cdn_dp_event_config(struct cdn_dp_device *dp)
+{
+	u8 msg[5];
+
+	msg[0] = DPTX_EVENT_ENABLE_HPD | DPTX_EVENT_ENABLE_TRAINING;
+
+	return cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_ENABLE_EVENT,
+				    ARRAY_SIZE(msg), msg);
+}
+
+int cdn_dp_get_event(struct cdn_dp_device *dp)
+{
+	return readl(dp->regs + SW_EVENTS0);
+}
+
+int cdn_dp_get_hpd_status(struct cdn_dp_device *dp)
+{
+	u8 *status = NULL;
+	int size;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_HPD_STATE,
+			    0, NULL);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_HPD_STATE, &status);
+	if (size != 1)
+		return -EINVAL;
+
+	return *status;
+}
+
+int cdn_dp_get_edid_block(void *data, u8 *edid,
+			  unsigned int block, size_t length)
+{
+	struct cdn_dp_device *dp = data;
+	int size;
+	u8 msg[2], *reg = NULL;
+
+	if (length != EDID_BLOCK_SIZE)
+		return -EINVAL;
+
+	msg[0] = block / 2;
+	msg[1] = block % 2;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_GET_EDID,
+			    2, msg);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_GET_EDID, &reg);
+
+	if (size != EDID_DATA + EDID_BLOCK_SIZE) {
+		dev_err(dp->dev, "read edid failed\n");
+		return -EINVAL;
+	}
+
+	if ((reg[EDID_LENGTH_BYTE] != EDID_BLOCK_SIZE) ||
+	    (reg[EDID_SEGMENT_BUMBER] != block / 2)) {
+		dev_err(dp->dev, "edid block size err\n");
+		return -EINVAL;
+	}
+
+	memcpy(edid, &reg[EDID_DATA], EDID_BLOCK_SIZE);
+
+	return 0;
+}
+
+int cdn_dp_training_start(struct cdn_dp_device *dp)
+{
+	int size;
+	u8 msg, *event = NULL;
+	unsigned long timeout;
+
+	msg = LINK_TRAINING_RUN;
+
+	/* start training */
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_TRAINING_CONTROL,
+			    1, &msg);
+
+	/* the whole training should finish in 500ms */
+	timeout = jiffies + msecs_to_jiffies(500);
+	while (1) {
+		msleep(20);
+		cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_EVENT,
+				    0, NULL);
+
+		size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+					       DPTX_READ_EVENT, &event);
+		if (size != 2)
+			return -EINVAL;
+
+		if (event[1] & EQ_PHASE_FINISHED)
+			break;
+
+		if (time_after(jiffies, timeout))
+			return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+int cdn_dp_get_lt_status(struct cdn_dp_device *dp)
+{
+	u8 *status = NULL;
+	int size;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_READ_LINK_STAT,
+			    0, NULL);
+
+	size = cdn_dp_mailbox_response(dp, MB_MODULE_ID_DP_TX,
+				       DPTX_READ_LINK_STAT, &status);
+
+	if (size != 10)
+		return -EINVAL;
+
+	dp->link.rate = status[0];
+	dp->link.num_lanes = status[1];
+
+	return 0;
+}
+
+int cdn_dp_set_video_status(struct cdn_dp_device *dp, int active)
+{
+	u8 msg;
+
+	msg = !!active;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_SET_VIDEO,
+			    1, &msg);
+
+	return 0;
+}
+
+int cdn_dp_set_audio_status(struct cdn_dp_device *dp, int active)
+{
+	u8 msg;
+
+	msg = !!active;
+
+	cdn_dp_mailbox_send(dp, MB_MODULE_ID_DP_TX, DPTX_SET_AUDIO,
+			    1, &msg);
+
+	return 0;
+}
+
+static int cdn_dp_get_msa_misc(struct video_info *video,
+			       struct drm_display_mode *mode)
+{
+	u8 val0, val1;
+	u32 msa_misc;
+
+	switch (video->color_fmt) {
+	case PXL_RGB:
+	case Y_ONLY:
+		val0 = 0;
+		break;
+	case YCBCR_4_4_4:
+		val0 = 6;
+		break;
+	case YCBCR_4_2_2:
+		val0 = 5;
+		break;
+	case YCBCR_4_2_0:
+		val0 = 5;
+		break;
+	};
+
+	switch (video->color_depth) {
+	case 6:
+		val1 = 0;
+		break;
+	case 8:
+		val1 = 1;
+		break;
+	case 10:
+		val1 = 2;
+		break;
+	case 12:
+		val1 = 3;
+		break;
+	case 16:
+		val1 = 4;
+		break;
+	};
+
+	msa_misc = 2 * val0 + 32 * val1 +
+		   ((video->color_fmt == Y_ONLY) ? (1 << 14) : 0);
+
+	return msa_misc;
+}
+
+int cdn_dp_config_video(struct cdn_dp_device *dp)
+{
+	struct video_info *video = &dp->video_info;
+	struct drm_display_mode *mode = &dp->mode;
+	u32 val, link_rate;
+	u8 bit_per_pix;
+
+	bit_per_pix = (video->color_fmt == YCBCR_4_2_2) ?
+		      (video->color_depth * 2) : (video->color_depth * 3);
+
+	val = VIF_BYPASS_INTERLACE;
+
+	cdn_dp_reg_write(dp, BND_HSYNC2VSYNC, val);
+
+	cdn_dp_reg_write(dp, HSYNC2VSYNC_POL_CTRL, 0);
+
+	link_rate = drm_dp_bw_code_to_link_rate(dp->link.rate) / 1000;
+
+	val = TU_SIZE * mode->clock * bit_per_pix;
+	val /= dp->link.num_lanes * link_rate * 8 * 1000;
+	/* FIXME: need add 1 to symbols 4K display */
+	if (mode->clock > 500000)
+		val += 1;
+
+	val += TU_SIZE << 8;
+
+	cdn_dp_reg_write(dp, DP_FRAMER_TU, val);
+
+	switch (video->color_depth) {
+	case 6:
+		val = BCS_6;
+		break;
+	case 8:
+		val = BCS_8;
+		break;
+	case 10:
+		val = BCS_10;
+		break;
+	case 12:
+		val = BCS_12;
+		break;
+	case 16:
+		val = BCS_16;
+		break;
+	};
+
+	val += video->color_fmt << 8;
+	cdn_dp_reg_write(dp, DP_FRAMER_PXL_REPR, val);
+
+	val = video->h_sync_polarity ? DP_FRAMER_SP_HSP : 0;
+	val |= video->v_sync_polarity ? DP_FRAMER_SP_VSP : 0;
+	cdn_dp_reg_write(dp, DP_FRAMER_SP, val);
+
+	val = (mode->hsync_start - mode->hdisplay) << 16;
+	val |= mode->htotal - mode->hsync_end;
+	cdn_dp_reg_write(dp, DP_FRONT_BACK_PORCH, val);
+
+	val = mode->hdisplay * bit_per_pix / 8;
+	cdn_dp_reg_write(dp, DP_BYTE_COUNT, val);
+
+	val = mode->htotal | ((mode->htotal - mode->hsync_start) << 16);
+	cdn_dp_reg_write(dp, MSA_HORIZONTAL_0, val);
+
+	val = mode->hsync_end - mode->hsync_start;
+	val |= (mode->hdisplay << 16) | (video->h_sync_polarity << 15);
+	cdn_dp_reg_write(dp, MSA_HORIZONTAL_1, val);
+
+	val = mode->vtotal;
+	val |= ((mode->vtotal - mode->vsync_start) << 16);
+
+	cdn_dp_reg_write(dp, MSA_VERTICAL_0, val);
+
+	val = mode->vsync_end - mode->vsync_start;
+	val |= mode->vdisplay << 16;
+	val |= (video->v_sync_polarity << 15);
+	cdn_dp_reg_write(dp, MSA_VERTICAL_1, val);
+
+	val = cdn_dp_get_msa_misc(video, mode);
+	cdn_dp_reg_write(dp, MSA_MISC, val);
+
+	cdn_dp_reg_write(dp, STREAM_CONFIG, 1);
+
+	val = mode->hsync_end - mode->hsync_start;
+	val |= (mode->hdisplay << 16);
+	cdn_dp_reg_write(dp, DP_HORIZONTAL, val);
+
+	val = mode->vtotal;
+	val -= (mode->vtotal - mode->vdisplay);
+	val |= (mode->vtotal - mode->vsync_start) << 16;
+
+	cdn_dp_reg_write(dp, DP_VERTICAL_0, val);
+
+	val = mode->vtotal;
+	cdn_dp_reg_write(dp, DP_VERTICAL_1, val);
+
+	val =  0;
+	cdn_dp_reg_write_bit(dp, DP_VB_ID, 2, 1, val);
+
+	return 0;
+}
+
+int cdn_dp_audio_start(void *dp_dev, struct audio_info *audio)
+{
+	struct cdn_dp_device *dp = (struct cdn_dp_device *)dp_dev;
+
+	if (audio->type == TYPE_SPDIF) {
+		clk_prepare_enable(dp->spdif_clk);
+		clk_set_rate(dp->spdif_clk, 400000000);
+	}
+
+	return cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN(1));
+}
+
+int cdn_dp_audio_stop(void *dp_dev, struct audio_info *audio)
+{
+	struct cdn_dp_device *dp = (struct cdn_dp_device *)dp_dev;
+
+	cdn_dp_reg_write(dp, AUDIO_PACK_CONTROL, AUDIO_PACK_EN(0));
+
+	if (audio->type == TYPE_SPDIF)
+		clk_disable_unprepare(dp->spdif_clk);
+
+	return 0;
+}
+
+int cdn_dp_audio_config_set(void *dp_dev, struct audio_info *audio)
+{
+	struct cdn_dp_device *dp = (struct cdn_dp_device *)dp_dev;
+	int lanes_param, i2s_port_en_val, val, i;
+
+	if ((audio->channels == 2) && (dp->link.num_lanes == 1))
+		lanes_param = 1;
+	else if (audio->channels == 2)
+		lanes_param = 3;
+	else
+		lanes_param = 0;
+
+	if (audio->channels == 2)
+		i2s_port_en_val = 1;
+	else if (audio->channels == 4)
+		i2s_port_en_val = 3;
+	else
+		i2s_port_en_val = 0xf;
+
+	cdn_dp_reg_write(dp, CM_LANE_CTRL, 0x8000);
+
+	cdn_dp_reg_write(dp, CM_CTRL, 0);
+
+	if (audio->type == TYPE_I2S) {
+		writel(0x0, dp->regs + SPDIF_CTRL_ADDR);
+
+		writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL);
+
+		val = audio->channels - 1;
+		val |= (audio->channels / 2 - 1) << 5;
+		val |= BIT(8);
+		val |= lanes_param << 11;
+		writel(val, dp->regs + SMPL2PKT_CNFG);
+
+		if (audio->word_length == 16)
+			val = 0;
+		else if (audio->word_length == 24)
+			val = 1 << 9;
+		else
+			val = 2 << 9;
+
+		val |= (audio->channels - 1) << 2;
+		val |= i2s_port_en_val << 17;
+		val |= 2 << 11;
+		writel(val, dp->regs + AUDIO_SRC_CNFG);
+
+		for (i = 0; i < (audio->channels + 1) / 2; i++) {
+			if (audio->word_length == 16)
+				val = (0x08 << 8) | (0x08 << 20);
+			else if (audio->word_length == 24)
+				val = (0x0b << 8) | (0x0b << 20);
+
+			val |= ((2 * i) << 4) | ((2 * i + 1) << 16);
+			writel(val, dp->regs + STTS_BIT_CH(i));
+		}
+
+		switch (audio->freq) {
+		case 32000:
+			val = SAMPLING_FREQ(3) |
+			      ORIGINAL_SAMP_FREQ(0xc);
+			break;
+		case 44100:
+			val = SAMPLING_FREQ(0) |
+			      ORIGINAL_SAMP_FREQ(0xf);
+			break;
+		case 48000:
+			val = SAMPLING_FREQ(2) |
+			      ORIGINAL_SAMP_FREQ(0xd);
+			break;
+		case 88200:
+			val = SAMPLING_FREQ(8) |
+			      ORIGINAL_SAMP_FREQ(0x7);
+			break;
+		case 96000:
+			val = SAMPLING_FREQ(0xa) |
+			      ORIGINAL_SAMP_FREQ(5);
+			break;
+		case 176400:
+			val = SAMPLING_FREQ(0xc) |
+			      ORIGINAL_SAMP_FREQ(3);
+			break;
+		case 192000:
+			val = SAMPLING_FREQ(0xe) |
+			      ORIGINAL_SAMP_FREQ(1);
+			break;
+		}
+		val |= 4;
+		writel(val, dp->regs + COM_CH_STTS_BITS);
+
+		writel(2, dp->regs + SMPL2PKT_CNTL);
+		writel(2, dp->regs + AUDIO_SRC_CNTL);
+		cdn_dp_reg_write_bit(dp, DP_VB_ID, 4, 1, 0);
+	} else {
+		val = 0x1F0707;
+		writel(val, dp->regs + SPDIF_CTRL_ADDR);
+
+		writel(SYNC_WR_TO_CH_ZERO, dp->regs + FIFO_CNTL);
+
+		val = 0x101 | (3 << 11);
+		writel(val, dp->regs + SMPL2PKT_CNFG);
+		writel(2, dp->regs + SMPL2PKT_CNTL);
+
+		val = 0x3F0707;
+		writel(val, dp->regs + SPDIF_CTRL_ADDR);
+	}
+
+	return 0;
+}
diff --git a/drivers/gpu/drm/rockchip/cdn-dp-reg.h b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
new file mode 100644
index 0000000..74fc7f9
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/cdn-dp-reg.h
@@ -0,0 +1,404 @@
+/*
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _CDN_DP_REG_H
+#define _CDN_DP_REG_H
+
+#include <linux/bitops.h>
+
+#define ADDR_IMEM		0x10000
+#define ADDR_DMEM		0x20000
+
+/* APB CFG addr */
+#define APB_CTRL			0
+#define XT_INT_CTRL			0x04
+#define MAILBOX_FULL_ADDR		0x08
+#define MAILBOX_EMPTY_ADDR		0x0c
+#define MAILBOX0_WR_DATA		0x10
+#define MAILBOX0_RD_DATA		0x14
+#define KEEP_ALIVE			0x18
+#define VER_L				0x1c
+#define VER_H				0x20
+#define VER_LIB_L_ADDR			0x24
+#define VER_LIB_H_ADDR			0x28
+#define SW_DEBUG_L			0x2c
+#define SW_DEBUG_H			0x30
+#define MAILBOX_INT_MASK		0x34
+#define MAILBOX_INT_STATUS		0x38
+#define SW_CLK_L			0x3c
+#define SW_CLK_H			0x40
+#define SW_EVENTS0			0x44
+#define SW_EVENTS1			0x48
+#define SW_EVENTS2			0x4c
+#define SW_EVENTS3			0x50
+#define XT_OCD_CTRL			0x60
+#define APB_INT_MASK			0x6c
+#define APB_STATUS_MASK			0x70
+
+/* audio decoder addr */
+#define AUDIO_SRC_CNTL			0x30000
+#define AUDIO_SRC_CNFG			0x30004
+#define COM_CH_STTS_BITS		0x30008
+#define STTS_BIT_CH(x)			(0x3000c + (x << 2))
+#define SPDIF_CTRL_ADDR			0x3004c
+#define SPDIF_CH1_CS_3100_ADDR		0x30050
+#define SPDIF_CH1_CS_6332_ADDR		0x30054
+#define SPDIF_CH1_CS_9564_ADDR		0x30058
+#define SPDIF_CH1_CS_12796_ADDR		0x3005c
+#define SPDIF_CH1_CS_159128_ADDR	0x30060
+#define SPDIF_CH1_CS_191160_ADDR	0x30064
+#define SPDIF_CH2_CS_3100_ADDR		0x30068
+#define SPDIF_CH2_CS_6332_ADDR		0x3006c
+#define SPDIF_CH2_CS_9564_ADDR		0x30070
+#define SPDIF_CH2_CS_12796_ADDR		0x30074
+#define SPDIF_CH2_CS_159128_ADDR	0x30078
+#define SPDIF_CH2_CS_191160_ADDR	0x3007c
+#define SMPL2PKT_CNTL			0x30080
+#define SMPL2PKT_CNFG			0x30084
+#define FIFO_CNTL			0x30088
+#define FIFO_STTS			0x3008c
+
+/* source pif addr */
+#define SOURCE_PIF_WR_ADDR		0x30800
+#define SOURCE_PIF_WR_REQ		0x30804
+#define SOURCE_PIF_RD_ADDR		0x30808
+#define SOURCE_PIF_RD_REQ		0x3080c
+#define SOURCE_PIF_DATA_WR		0x30810
+#define SOURCE_PIF_DATA_RD		0x30814
+#define SOURCE_PIF_FIFO1_FLUSH		0x30818
+#define SOURCE_PIF_FIFO2_FLUSH		0x3081c
+#define SOURCE_PIF_STATUS		0x30820
+#define SOURCE_PIF_INTERRUPT_SOURCE	0x30824
+#define SOURCE_PIF_INTERRUPT_MASK	0x30828
+#define SOURCE_PIF_PKT_ALLOC_REG	0x3082c
+#define SOURCE_PIF_PKT_ALLOC_WR_EN	0x30830
+#define SOURCE_PIF_SW_RESET		0x30834
+
+/* bellow registers need access by mailbox */
+/* source car addr */
+#define SOURCE_HDTX_CAR			0x0900
+#define SOURCE_DPTX_CAR			0x0904
+#define SOURCE_PHY_CAR			0x0908
+#define SOURCE_CEC_CAR			0x090c
+#define SOURCE_CBUS_CAR			0x0910
+#define SOURCE_PKT_CAR			0x0918
+#define SOURCE_AIF_CAR			0x091c
+#define SOURCE_CIPHER_CAR		0x0920
+#define SOURCE_CRYPTO_CAR		0x0924
+
+/* clock meters addr */
+#define CM_CTRL				0x0a00
+#define CM_I2S_CTRL			0x0a04
+#define CM_SPDIF_CTRL			0x0a08
+#define CM_VID_CTRL			0x0a0c
+#define CM_LANE_CTRL			0x0a10
+#define I2S_NM_STABLE			0x0a14
+#define I2S_NCTS_STABLE			0x0a18
+#define SPDIF_NM_STABLE			0x0a1c
+#define SPDIF_NCTS_STABLE		0x0a20
+#define NMVID_MEAS_STABLE		0x0a24
+#define I2S_MEAS			0x0a40
+#define SPDIF_MEAS			0x0a80
+#define NMVID_MEAS			0x0ac0
+
+/* source vif addr */
+#define BND_HSYNC2VSYNC			0x0b00
+#define HSYNC2VSYNC_F1_L1		0x0b04
+#define HSYNC2VSYNC_F2_L1		0x0b08
+#define HSYNC2VSYNC_STATUS		0x0b0c
+#define HSYNC2VSYNC_POL_CTRL		0x0b10
+
+/* dptx phy addr */
+#define DP_TX_PHY_CONFIG_REG		0x2000
+#define DP_TX_PHY_STATUS_REG		0x2004
+#define DP_TX_PHY_SW_RESET		0x2008
+#define DP_TX_PHY_SCRAMBLER_SEED	0x200c
+#define DP_TX_PHY_TRAINING_01_04	0x2010
+#define DP_TX_PHY_TRAINING_05_08	0x2014
+#define DP_TX_PHY_TRAINING_09_10	0x2018
+#define TEST_COR			0x23fc
+
+/* dptx hpd addr */
+#define HPD_IRQ_DET_MIN_TIMER		0x2100
+#define HPD_IRQ_DET_MAX_TIMER		0x2104
+#define HPD_UNPLGED_DET_MIN_TIMER	0x2108
+#define HPD_STABLE_TIMER		0x210c
+#define HPD_FILTER_TIMER		0x2110
+#define HPD_EVENT_MASK			0x211c
+#define HPD_EVENT_DET			0x2120
+
+/* dpyx framer addr */
+#define DP_FRAMER_GLOBAL_CONFIG		0x2200
+#define DP_SW_RESET			0x2204
+#define DP_FRAMER_TU			0x2208
+#define DP_FRAMER_PXL_REPR		0x220c
+#define DP_FRAMER_SP			0x2210
+#define AUDIO_PACK_CONTROL		0x2214
+#define DP_VC_TABLE(x)			(0x2218 + (x << 2))
+#define DP_VB_ID			0x2258
+#define DP_MTPH_LVP_CONTROL		0x225c
+#define DP_MTPH_SYMBOL_VALUES		0x2260
+#define DP_MTPH_ECF_CONTROL		0x2264
+#define DP_MTPH_ACT_CONTROL		0x2268
+#define DP_MTPH_STATUS			0x226c
+#define DP_INTERRUPT_SOURCE		0x2270
+#define DP_INTERRUPT_MASK		0x2274
+#define DP_FRONT_BACK_PORCH		0x2278
+#define DP_BYTE_COUNT			0x227c
+
+/* dptx stream addr */
+#define MSA_HORIZONTAL_0		0x2280
+#define MSA_HORIZONTAL_1		0x2284
+#define MSA_VERTICAL_0			0x2288
+#define MSA_VERTICAL_1			0x228c
+#define MSA_MISC			0x2290
+#define STREAM_CONFIG			0x2294
+#define AUDIO_PACK_STATUS		0x2298
+#define VIF_STATUS			0x229c
+#define PCK_STUFF_STATUS_0		0x22a0
+#define PCK_STUFF_STATUS_1		0x22a4
+#define INFO_PACK_STATUS		0x22a8
+#define RATE_GOVERNOR_STATUS		0x22ac
+#define DP_HORIZONTAL			0x22b0
+#define DP_VERTICAL_0			0x22b4
+#define DP_VERTICAL_1			0x22b8
+#define DP_BLOCK_SDP			0x22bc
+
+/* dptx glbl addr */
+#define DPTX_LANE_EN			0x2300
+#define DPTX_ENHNCD			0x2304
+#define DPTX_INT_MASK			0x2308
+#define DPTX_INT_STATUS			0x230c
+
+/* dp aux addr */
+#define DP_AUX_HOST_CONTROL		0x2800
+#define DP_AUX_INTERRUPT_SOURCE		0x2804
+#define DP_AUX_INTERRUPT_MASK		0x2808
+#define DP_AUX_SWAP_INVERSION_CONTROL	0x280c
+#define DP_AUX_SEND_NACK_TRANSACTION	0x2810
+#define DP_AUX_CLEAR_RX			0x2814
+#define DP_AUX_CLEAR_TX			0x2818
+#define DP_AUX_TIMER_STOP		0x281c
+#define DP_AUX_TIMER_CLEAR		0x2820
+#define DP_AUX_RESET_SW			0x2824
+#define DP_AUX_DIVIDE_2M		0x2828
+#define DP_AUX_TX_PREACHARGE_LENGTH	0x282c
+#define DP_AUX_FREQUENCY_1M_MAX		0x2830
+#define DP_AUX_FREQUENCY_1M_MIN		0x2834
+#define DP_AUX_RX_PRE_MIN		0x2838
+#define DP_AUX_RX_PRE_MAX		0x283c
+#define DP_AUX_TIMER_PRESET		0x2840
+#define DP_AUX_NACK_FORMAT		0x2844
+#define DP_AUX_TX_DATA			0x2848
+#define DP_AUX_RX_DATA			0x284c
+#define DP_AUX_TX_STATUS		0x2850
+#define DP_AUX_RX_STATUS		0x2854
+#define DP_AUX_RX_CYCLE_COUNTER		0x2858
+#define DP_AUX_MAIN_STATES		0x285c
+#define DP_AUX_MAIN_TIMER		0x2860
+#define DP_AUX_AFE_OUT			0x2864
+
+/* crypto addr */
+#define CRYPTO_HDCP_REVISION		0x5800
+#define HDCP_CRYPTO_CONFIG		0x5804
+#define CRYPTO_INTERRUPT_SOURCE		0x5808
+#define CRYPTO_INTERRUPT_MASK		0x580c
+#define CRYPTO22_CONFIG			0x5818
+#define CRYPTO22_STATUS			0x581c
+#define SHA_256_DATA_IN			0x583c
+#define SHA_256_DATA_OUT_(x)		(0x5850 + (x << 2))
+#define AES_32_KEY_(x)			(0x5870 + (x << 2))
+#define AES_32_DATA_IN			0x5880
+#define AES_32_DATA_OUT_(x)		(0x5884 + (x << 2))
+#define CRYPTO14_CONFIG			0x58a0
+#define CRYPTO14_STATUS			0x58a4
+#define CRYPTO14_PRNM_OUT		0x58a8
+#define CRYPTO14_KM_0			0x58ac
+#define CRYPTO14_KM_1			0x58b0
+#define CRYPTO14_AN_0			0x58b4
+#define CRYPTO14_AN_1			0x58b8
+#define CRYPTO14_YOUR_KSV_0		0x58bc
+#define CRYPTO14_YOUR_KSV_1		0x58c0
+#define CRYPTO14_MI_0			0x58c4
+#define CRYPTO14_MI_1			0x58c8
+#define CRYPTO14_TI_0			0x58cc
+#define CRYPTO14_KI_0			0x58d0
+#define CRYPTO14_KI_1			0x58d4
+#define CRYPTO14_BLOCKS_NUM		0x58d8
+#define CRYPTO14_KEY_MEM_DATA_0		0x58dc
+#define CRYPTO14_KEY_MEM_DATA_1		0x58e0
+#define CRYPTO14_SHA1_MSG_DATA		0x58e4
+#define CRYPTO14_SHA1_V_VALUE_(x)	(0x58e8 + (x << 2))
+#define TRNG_CTRL			0x58fc
+#define TRNG_DATA_RDY			0x5900
+#define TRNG_DATA			0x5904
+
+/* cipher addr */
+#define HDCP_REVISION			0x60000
+#define INTERRUPT_SOURCE		0x60004
+#define INTERRUPT_MASK			0x60008
+#define HDCP_CIPHER_CONFIG		0x6000c
+#define AES_128_KEY_0			0x60010
+#define AES_128_KEY_1			0x60014
+#define AES_128_KEY_2			0x60018
+#define AES_128_KEY_3			0x6001c
+#define AES_128_RANDOM_0		0x60020
+#define AES_128_RANDOM_1		0x60024
+#define CIPHER14_KM_0			0x60028
+#define CIPHER14_KM_1			0x6002c
+#define CIPHER14_STATUS			0x60030
+#define CIPHER14_RI_PJ_STATUS		0x60034
+#define CIPHER_MODE			0x60038
+#define CIPHER14_AN_0			0x6003c
+#define CIPHER14_AN_1			0x60040
+#define CIPHER22_AUTH			0x60044
+#define CIPHER14_R0_DP_STATUS		0x60048
+#define CIPHER14_BOOTSTRAP		0x6004c
+
+#define APB_IRAM_PATH			BIT(2)
+#define APB_DRAM_PATH			BIT(1)
+#define APB_XT_RESET			BIT(0)
+
+/* mailbox */
+#define MB_OPCODE_ID			0
+#define MB_MODULE_ID			1
+#define MB_SIZE_MSB_ID			2
+#define MB_SIZE_LSB_ID			3
+#define MB_DATA_ID			4
+
+#define MB_MODULE_ID_DP_TX		0x01
+#define MB_MODULE_ID_HDCP_TX		0x07
+#define MB_MODULE_ID_HDCP_RX		0x08
+#define MB_MODULE_ID_HDCP_GENERAL	0x09
+#define MB_MODULE_ID_GENERAL		0x0a
+
+/* general opcode */
+#define GENERAL_MAIN_CONTROL            0x01
+#define GENERAL_TEST_ECHO               0x02
+#define GENERAL_BUS_SETTINGS            0x03
+#define GENERAL_TEST_ACCESS             0x04
+
+#define DPTX_SET_POWER_MNG			0x00
+#define DPTX_SET_HOST_CAPABILITIES		0x01
+#define DPTX_GET_EDID				0x02
+#define DPTX_READ_DPCD				0x03
+#define DPTX_WRITE_DPCD				0x04
+#define DPTX_ENABLE_EVENT			0x05
+#define DPTX_WRITE_REGISTER			0x06
+#define DPTX_READ_REGISTER			0x07
+#define DPTX_WRITE_FIELD			0x08
+#define DPTX_TRAINING_CONTROL			0x09
+#define DPTX_READ_EVENT				0x0a
+#define DPTX_READ_LINK_STAT			0x0b
+#define DPTX_SET_VIDEO				0x0c
+#define DPTX_SET_AUDIO				0x0d
+#define DPTX_GET_LAST_AUX_STAUS			0x0e
+#define DPTX_SET_LINK_BREAK_POINT		0x0f
+#define DPTX_FORCE_LANES			0x10
+#define DPTX_HPD_STATE				0x11
+
+#define DPTX_EVENT_ENABLE_HPD			BIT(0)
+#define DPTX_EVENT_ENABLE_TRAINING		BIT(1)
+
+#define LINK_TRAINING_NOT_ACTIVE		0
+#define LINK_TRAINING_RUN			1
+#define LINK_TRAINING_RESTART			2
+
+#define CONTROL_VIDEO_IDLE			0
+#define CONTROL_VIDEO_VALID			1
+
+#define VIF_BYPASS_INTERLACE			BIT(13)
+#define INTERLACE_FMT_DET			BIT(12)
+#define INTERLACE_DTCT_WIN			0x20
+
+#define DP_FRAMER_SP_INTERLACE_EN		BIT(2)
+#define DP_FRAMER_SP_HSP			BIT(1)
+#define DP_FRAMER_SP_VSP			BIT(0)
+
+/* capability */
+#define AUX_HOST_INVERT				3
+#define	FAST_LT_SUPPORT				1
+#define FAST_LT_NOT_SUPPORT			0
+#define LANE_MAPPING_NORMAL			0xe4
+#define LANE_MAPPING_FLIPPED			0x1b
+#define ENHANCED				1
+
+#define	FULL_LT_STARTED				BIT(0)
+#define FASE_LT_STARTED				BIT(1)
+#define CLK_RECOVERY_FINISHED			BIT(2)
+#define EQ_PHASE_FINISHED			BIT(3)
+#define FASE_LT_START_FINISHED			BIT(4)
+#define CLK_RECOVERY_FAILED			BIT(5)
+#define EQ_PHASE_FAILED				BIT(6)
+#define FASE_LT_FAILED				BIT(7)
+
+#define DPTX_HPD_EVENT				BIT(0)
+#define DPTX_TRAINING_EVENT			BIT(1)
+#define HDCP_TX_STATUS_EVENT			BIT(4)
+#define HDCP2_TX_IS_KM_STORED_EVENT		BIT(5)
+#define HDCP2_TX_STORE_KM_EVENT			BIT(6)
+#define HDCP_TX_IS_RECEIVER_ID_VALID_EVENT	BIT(7)
+
+#define EDID_LENGTH_BYTE			0
+#define EDID_SEGMENT_BUMBER			1
+#define EDID_DATA				2
+#define EDID_BLOCK_SIZE				128
+
+#define TU_SIZE					64
+
+/* audio */
+#define AUDIO_PACK_EN(x)			(x << 8)
+#define SAMPLING_FREQ(x)			(x << 16)
+#define ORIGINAL_SAMP_FREQ(x)			(x << 24)
+#define SYNC_WR_TO_CH_ZERO			BIT(1)
+
+enum voltage_swing_level {
+	VOLTAGE_LEVEL_0,
+	VOLTAGE_LEVEL_1,
+	VOLTAGE_LEVEL_2,
+	VOLTAGE_LEVEL_3,
+};
+
+enum pre_emphasis_level {
+	PRE_EMPHASIS_LEVEL_0,
+	PRE_EMPHASIS_LEVEL_1,
+	PRE_EMPHASIS_LEVEL_2,
+	PRE_EMPHASIS_LEVEL_3,
+};
+
+enum pattern_set {
+	PRBS7		= BIT(0),
+	D10_2		= BIT(1),
+	TRAINING_PTN1	= BIT(2),
+	TRAINING_PTN2	= BIT(3),
+	DP_NONE		= BIT(4)
+};
+
+enum VIC_PXL_ENCODING_FORMAT {
+	PXL_RGB = 0x1,
+	YCBCR_4_4_4 = 0x2,
+	YCBCR_4_2_2 = 0x4,
+	YCBCR_4_2_0 = 0x8,
+	Y_ONLY = 0x10,
+};
+
+enum VIC_COLOR_DEPTH {
+	BCS_6 = 0x1,
+	BCS_8 = 0x2,
+	BCS_10 = 0x4,
+	BCS_12 = 0x8,
+	BCS_16 = 0x10,
+};
+
+#endif /* _CDN_DP_REG_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index edd7ec2..623d9e3 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -969,7 +969,10 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
 		vop_dsp_hold_valid_irq_disable(vop);
 	}
 
-	pin_pol = 0x8;
+	if (s->output_type != DRM_MODE_CONNECTOR_DisplayPort)
+		pin_pol = 0x8;
+	else
+		pin_pol = 0;
 	pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NHSYNC) ? 0 : 1;
 	pin_pol |= (adjusted_mode->flags & DRM_MODE_FLAG_NVSYNC) ? 0 : (1 << 1);
 	VOP_CTRL_SET(vop, pin_pol, pin_pol);
@@ -991,6 +994,10 @@ static void vop_crtc_enable(struct drm_crtc *crtc)
 		VOP_CTRL_SET(vop, mipi_pin_pol, pin_pol);
 		VOP_CTRL_SET(vop, mipi_en, 1);
 		break;
+	case DRM_MODE_CONNECTOR_DisplayPort:
+		VOP_CTRL_SET(vop, dp_pin_pol, pin_pol);
+		VOP_CTRL_SET(vop, dp_en, 1);
+		break;
 	default:
 		DRM_ERROR("unsupport connector_type[%d]\n", s->output_type);
 	}
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index ff4f52e..50a045c 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -45,6 +45,7 @@ struct vop_ctrl {
 	struct vop_reg edp_en;
 	struct vop_reg hdmi_en;
 	struct vop_reg mipi_en;
+	struct vop_reg dp_en;
 	struct vop_reg out_mode;
 	struct vop_reg dither_down;
 	struct vop_reg dither_up;
@@ -53,6 +54,7 @@ struct vop_ctrl {
 	struct vop_reg hdmi_pin_pol;
 	struct vop_reg edp_pin_pol;
 	struct vop_reg mipi_pin_pol;
+	struct vop_reg dp_pin_pol;
 
 	struct vop_reg htotal_pw;
 	struct vop_reg hact_st_end;
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 5b1ae1f..dcf172e 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -281,6 +281,7 @@ static const struct vop_data rk3288_vop = {
 static const struct vop_ctrl rk3399_ctrl_data = {
 	.standby = VOP_REG(RK3399_SYS_CTRL, 0x1, 22),
 	.gate_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 23),
+	.dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11),
 	.rgb_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 12),
 	.hdmi_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 13),
 	.edp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 14),
@@ -290,6 +291,7 @@ static const struct vop_ctrl rk3399_ctrl_data = {
 	.data_blank = VOP_REG(RK3399_DSP_CTRL0, 0x1, 19),
 	.out_mode = VOP_REG(RK3399_DSP_CTRL0, 0xf, 0),
 	.rgb_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16),
+	.dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16),
 	.hdmi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 20),
 	.edp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 24),
 	.mipi_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 28),
diff --git a/include/sound/cdn-dp-audio.h b/include/sound/cdn-dp-audio.h
new file mode 100644
index 0000000..8c6e55c
--- /dev/null
+++ b/include/sound/cdn-dp-audio.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __CDN_DP_AUDIO_H__
+#define __CDN_DP_AUDIO_H__
+
+#include <linux/platform_device.h>
+
+#define AUDIO_TYPE_I2S			0
+#define AUDIO_TYPE_SPIDIF_INTERNAL	1
+#define AUDIO_TYPE_SPIDIF_EXTERNAL	2
+
+enum AUDIO_TYPE {
+	TYPE_I2S = 0,
+	TYPE_SPDIF = 1,
+};
+
+struct audio_info {
+	enum AUDIO_TYPE type;
+	int freq;
+	int channels;
+	int word_length;
+};
+
+struct cdn_dp_audio_ops {
+	int (*audio_startup)(void *dp_dev, struct audio_info *audio);
+	int (*audio_shutdown)(void *dp_dev, struct audio_info *audio);
+	int (*audio_start)(void *dp_dev, struct audio_info *audio);
+	int (*audio_stop)(void *dp_dev, struct audio_info *audio);
+	int (*audio_config)(void *dp_dev, struct audio_info *audio);
+};
+
+/* DP audio initalization data */
+struct cdn_dp_audio_pdata {
+	struct device *dev;
+	const struct cdn_dp_audio_ops *ops;
+	void *data;
+};
+
+#endif /* __CDN_DP_AUDIO_H__ */
-- 
2.6.3



From zyw at rock-chips.com  Fri May 27 03:45:42 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 18:45:42 +0800
Subject: [RESEND PATCH 6/6] ASoC: rockchip: Add machine driver for cdn dp codec
In-Reply-To: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
References: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464345942-4795-7-git-send-email-zyw@rock-chips.com>

The driver is used for cdn dp codec embedded in rk3399

Signed-off-by: Chris Zhong <zyw at rock-chips.com>

---

 .../bindings/sound/rockchip-cdn-dp-audio.txt       |  12 ++
 sound/soc/rockchip/Kconfig                         |   9 ++
 sound/soc/rockchip/Makefile                        |   2 +
 sound/soc/rockchip/rockchip-cdn-dp-audio.c         | 167 +++++++++++++++++++++
 4 files changed, 190 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/sound/rockchip-cdn-dp-audio.txt
 create mode 100644 sound/soc/rockchip/rockchip-cdn-dp-audio.c

diff --git a/Documentation/devicetree/bindings/sound/rockchip-cdn-dp-audio.txt b/Documentation/devicetree/bindings/sound/rockchip-cdn-dp-audio.txt
new file mode 100644
index 0000000..b7b0898
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rockchip-cdn-dp-audio.txt
@@ -0,0 +1,12 @@
+Rockchip cdn dp audio bindings
+
+Required properties:
+- compatible: platform specific, must be "rockchip,cdn-dp-audio"
+- i2s-controller: the device of i2s controller
+
+Example:
+
+	cdn_dp_audio: cdn-dp_audio {
+		compatible = "rockchip,cdn-dp-audio";
+		i2s-controller = <&i2s2>;
+	};
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index f1e0c70..7e7d905 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -15,6 +15,15 @@ config SND_SOC_ROCKCHIP_I2S
 	  Rockchip I2S device. The device supports upto maximum of
 	  8 channels each for play and record.
 
+config SND_SOC_ROCKCHIP_CDN_DP_AUDIO
+	tristate "cdn DP audio support"
+	depends on ROCKCHIP_CDN_DP
+	select SND_SOC_ROCKCHIP_I2S
+	select SND_SOC_CDN_DP_AUDIO
+	help
+	  Say Y or M here if you want to add support for SoC audio on Rockchip
+	  boards using the cdn dp codec, such as RK3399.
+
 config SND_SOC_ROCKCHIP_SPDIF
 	tristate "Rockchip SPDIF Device Driver"
 	depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP
diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
index c0bf560..9367f55 100644
--- a/sound/soc/rockchip/Makefile
+++ b/sound/soc/rockchip/Makefile
@@ -5,8 +5,10 @@ snd-soc-rockchip-spdif-objs := rockchip_spdif.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_I2S) += snd-soc-rockchip-i2s.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
 
+snd-soc-rockchip-cdn-dp-objs := rockchip-cdn-dp-audio.o
 snd-soc-rockchip-max98090-objs := rockchip_max98090.o
 snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
 
+obj-$(CONFIG_SND_SOC_ROCKCHIP_CDN_DP_AUDIO) += snd-soc-rockchip-cdn-dp.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
 obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
diff --git a/sound/soc/rockchip/rockchip-cdn-dp-audio.c b/sound/soc/rockchip/rockchip-cdn-dp-audio.c
new file mode 100644
index 0000000..2bf6649
--- /dev/null
+++ b/sound/soc/rockchip/rockchip-cdn-dp-audio.c
@@ -0,0 +1,167 @@
+/*
+ * rockchip-cdn-dp-card.c
+ *
+ * ROCKCHIP ALSA SoC DAI driver for cdn dp audio on rockchip processors.
+ *
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <sound/soc.h>
+#include <sound/pcm.h>
+#include <sound/core.h>
+#include <sound/pcm_params.h>
+
+#include "rockchip_i2s.h"
+
+#define DRV_NAME "rockchip-cdn-dp-audio"
+
+static int cdn_dp_audio_hw_params(struct snd_pcm_substream *substream,
+				  struct snd_pcm_hw_params *params)
+{
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+	unsigned int dai_fmt = rtd->dai_link->dai_fmt;
+	int mclk, ret;
+
+	switch (params_rate(params)) {
+	case 8000:
+	case 16000:
+	case 24000:
+	case 32000:
+	case 48000:
+	case 64000:
+	case 96000:
+		mclk = 12288000;
+		break;
+	case 11025:
+	case 22050:
+	case 44100:
+	case 88200:
+		mclk = 11289600;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = snd_soc_dai_set_fmt(cpu_dai, dai_fmt);
+	if (ret < 0) {
+		dev_err(cpu_dai->dev, "failed to set cpu_dai fmt.\n");
+		return ret;
+	}
+
+	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, SND_SOC_CLOCK_OUT);
+	if (ret < 0) {
+		dev_err(cpu_dai->dev, "failed to set cpu_dai sysclk.\n");
+		return ret;
+	}
+
+	return 0;
+}
+
+static struct snd_soc_ops cdn_dp_dai_ops = {
+	.hw_params = cdn_dp_audio_hw_params,
+};
+
+static struct snd_soc_dai_link cdn_dp_dai = {
+	.name = "cdn_dp",
+	.stream_name = "cdn_dp",
+	.codec_name = "cdn-dp-audio",
+	.codec_dai_name = "cdn-dp-hifi",
+	.ops = &cdn_dp_dai_ops,
+	.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
+		   SND_SOC_DAIFMT_CBS_CFS,
+};
+
+static struct snd_soc_card cdn_dp_audio_card = {
+	.name = "cdn_dp",
+	.owner = THIS_MODULE,
+	.dai_link = &cdn_dp_dai,
+	.num_links = 1,
+};
+
+static int cdn_dp_audio_probe(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = &cdn_dp_audio_card;
+	struct device_node *np = pdev->dev.of_node;
+	int ret;
+
+	card->dev = &pdev->dev;
+	platform_set_drvdata(pdev, card);
+
+	cdn_dp_dai.cpu_of_node = of_parse_phandle(np, "i2s-controller", 0);
+	if (!cdn_dp_dai.cpu_of_node) {
+		dev_err(&pdev->dev, "Property 'i2s-controller' missing !\n");
+		goto free_priv_data;
+	}
+
+	cdn_dp_dai.platform_of_node = cdn_dp_dai.cpu_of_node;
+
+	ret = snd_soc_register_card(card);
+	if (ret) {
+		dev_err(&pdev->dev, "register card failed (%d)\n", ret);
+		card->dev = NULL;
+		goto free_cpu_of_node;
+	}
+
+	dev_info(&pdev->dev, "rockchip cdn dp audio init success.\n");
+
+	return 0;
+
+free_cpu_of_node:
+	cdn_dp_dai.cpu_of_node = NULL;
+	cdn_dp_dai.platform_of_node = NULL;
+free_priv_data:
+	snd_soc_card_set_drvdata(card, NULL);
+	platform_set_drvdata(pdev, NULL);
+	card->dev = NULL;
+
+	return ret;
+}
+
+static int cdn_dp_audio_remove(struct platform_device *pdev)
+{
+	struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+	snd_soc_unregister_card(card);
+	snd_soc_card_set_drvdata(card, NULL);
+	platform_set_drvdata(pdev, NULL);
+	card->dev = NULL;
+
+	return 0;
+}
+
+static const struct of_device_id cdn_dp_audio_of_match[] = {
+	{ .compatible = "rockchip,cdn-dp-audio", },
+	{},
+};
+
+static struct platform_driver cdn_dp_audio_driver = {
+	.driver = {
+		.name = DRV_NAME,
+		.owner = THIS_MODULE,
+		.pm = &snd_soc_pm_ops,
+		.of_match_table = cdn_dp_audio_of_match,
+	},
+	.probe = cdn_dp_audio_probe,
+	.remove = cdn_dp_audio_remove,
+};
+module_platform_driver(cdn_dp_audio_driver);
+
+MODULE_AUTHOR("Chris Zhong <zyw at rock-chips.com>");
+MODULE_DESCRIPTION("CDN DP Audio ASoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
+MODULE_DEVICE_TABLE(of, cdn_dp_audio_of_match);
-- 
2.6.3



From zyw at rock-chips.com  Fri May 27 03:45:41 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Fri, 27 May 2016 18:45:41 +0800
Subject: [RESEND PATCH 5/6] ASoC: cdn-dp: Add cdn DP codec driver
In-Reply-To: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
References: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
Message-ID: <1464345942-4795-6-git-send-email-zyw@rock-chips.com>

codec driver get some interfaces from cdn-dp driver, than using those
to set DP audio formats, corresponding to alsa formats.

Signed-off-by: Chris Zhong <zyw at rock-chips.com>
---

 sound/soc/codecs/Kconfig        |   3 +
 sound/soc/codecs/Makefile       |   2 +
 sound/soc/codecs/cdn-dp-audio.c | 246 ++++++++++++++++++++++++++++++++++++++++
 3 files changed, 251 insertions(+)
 create mode 100644 sound/soc/codecs/cdn-dp-audio.c

diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 7ef3a0c..7ddae65 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -365,6 +365,9 @@ config SND_SOC_ALC5623
 config SND_SOC_ALC5632
 	tristate
 
+config SND_SOC_CDN_DP_AUDIO
+	tristate
+
 config SND_SOC_CQ0093VC
 	tristate
 
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 185a712..7a703a7 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -32,6 +32,7 @@ snd-soc-ak4642-objs := ak4642.o
 snd-soc-ak4671-objs := ak4671.o
 snd-soc-ak5386-objs := ak5386.o
 snd-soc-arizona-objs := arizona.o
+snd-soc-cdn-dp-audio-objs := cdn-dp-audio.o
 snd-soc-cq93vc-objs := cq93vc.o
 snd-soc-cs35l32-objs := cs35l32.o
 snd-soc-cs42l51-objs := cs42l51.o
@@ -241,6 +242,7 @@ obj-$(CONFIG_SND_SOC_AK5386)	+= snd-soc-ak5386.o
 obj-$(CONFIG_SND_SOC_ALC5623)    += snd-soc-alc5623.o
 obj-$(CONFIG_SND_SOC_ALC5632)	+= snd-soc-alc5632.o
 obj-$(CONFIG_SND_SOC_ARIZONA)	+= snd-soc-arizona.o
+obj-$(CONFIG_SND_SOC_CDN_DP_AUDIO) += snd-soc-cdn-dp-audio.o
 obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o
 obj-$(CONFIG_SND_SOC_CS35L32)	+= snd-soc-cs35l32.o
 obj-$(CONFIG_SND_SOC_CS42L51)	+= snd-soc-cs42l51.o
diff --git a/sound/soc/codecs/cdn-dp-audio.c b/sound/soc/codecs/cdn-dp-audio.c
new file mode 100644
index 0000000..a68570f
--- /dev/null
+++ b/sound/soc/codecs/cdn-dp-audio.c
@@ -0,0 +1,246 @@
+/*
+ * cdn dp audio support library
+ *
+ * Copyright (C) 2016 Chris Zhong <zyw at rock-chips.com>
+ * Copyright (C) 2016 ROCKCHIP, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/moduleparam.h>
+
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm_params.h>
+
+#include <sound/cdn-dp-audio.h>
+
+#define DRV_NAME "cdn-dp-audio"
+
+struct snd_cdn_dp_audio {
+	struct device *dev;
+	const struct cdn_dp_audio_ops *ops;
+	void *data;
+	bool is_playback_status;
+};
+
+static int snd_cdn_dp_audio_dai_startup(struct snd_pcm_substream *substream,
+					struct snd_soc_dai *codec_dai)
+{
+	struct snd_cdn_dp_audio *ad = snd_soc_dai_get_drvdata(codec_dai);
+	struct audio_info audio;
+
+	ad->is_playback_status = true;
+	ad->ops->audio_startup(ad->data, &audio);
+
+	return 0;
+}
+
+static int snd_cdn_dp_audio_dai_hw_params(struct snd_pcm_substream *substream,
+					  struct snd_pcm_hw_params *params,
+					  struct snd_soc_dai *codec_dai)
+{
+	struct snd_cdn_dp_audio *ad = snd_soc_dai_get_drvdata(codec_dai);
+	struct snd_soc_pcm_runtime *rtd = substream->private_data;
+	struct audio_info audio;
+	unsigned int fmt, rate, chan, width;
+
+	fmt = rtd->dai_link->dai_fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+	if (fmt == SND_SOC_DAIFMT_I2S) {
+		audio.type = AUDIO_TYPE_I2S;
+	} else {
+		dev_err(codec_dai->dev, "DAI format unsupported");
+		return -EINVAL;
+	}
+
+	width = params_width(params);
+	if ((width == 16) || (width == 24)) {
+		audio.word_length = width;
+	} else {
+		dev_err(codec_dai->dev, "width[%d] not support!\n", width);
+		return -EINVAL;
+	}
+
+	chan = params_channels(params);
+	switch (chan) {
+	case 2:
+	case 4:
+	case 6:
+	case 8:
+		audio.channels = chan;
+		break;
+	default:
+		dev_err(codec_dai->dev, "channel[%d] not support!\n", chan);
+		return -EINVAL;
+	}
+
+	rate = params_rate(params);
+	switch (rate) {
+	case 32000:
+	case 44100:
+	case 48000:
+	case 88200:
+	case 96000:
+	case 176400:
+	case 192000:
+		audio.freq = rate;
+		break;
+	default:
+		dev_err(codec_dai->dev, "rate[%d] not support!\n", rate);
+		return -EINVAL;
+	}
+
+	ad->ops->audio_config(ad->data, &audio);
+
+	return 0;
+}
+
+static int snd_cdn_dp_audio_dai_trigger(struct snd_pcm_substream *substream,
+					int cmd, struct snd_soc_dai *codec_dai)
+{
+	struct snd_cdn_dp_audio *ad = snd_soc_dai_get_drvdata(codec_dai);
+	struct audio_info audio;
+
+	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_START:
+	case SNDRV_PCM_TRIGGER_RESUME:
+	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+		ad->ops->audio_start(ad->data, &audio);
+		break;
+	case SNDRV_PCM_TRIGGER_STOP:
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+		ad->ops->audio_stop(ad->data, &audio);
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void snd_cdn_dp_audio_dai_shutdown(struct snd_pcm_substream *substream,
+					  struct snd_soc_dai *codec_dai)
+{
+	struct snd_cdn_dp_audio *ad = snd_soc_dai_get_drvdata(codec_dai);
+	struct audio_info audio;
+
+	ad->is_playback_status = false;
+	ad->ops->audio_shutdown(ad->data, &audio);
+}
+
+static const struct snd_soc_dapm_widget snd_cdn_dp_audio_widgets[] = {
+	SND_SOC_DAPM_OUTPUT("TX"),
+};
+
+static const struct snd_soc_dapm_route snd_cdn_dp_audio_routes[] = {
+	{ "TX", NULL, "Playback" },
+};
+
+static const struct snd_soc_dai_ops cdn_dp_audio_dai_ops = {
+	.startup = snd_cdn_dp_audio_dai_startup,
+	.hw_params = snd_cdn_dp_audio_dai_hw_params,
+	.trigger = snd_cdn_dp_audio_dai_trigger,
+	.shutdown = snd_cdn_dp_audio_dai_shutdown,
+};
+
+static struct snd_soc_dai_driver cdn_dp_audio_dai = {
+	.name = "cdn-dp-hifi",
+	.playback = {
+		.stream_name = "Playback",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_32000 |
+			 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+			 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+	.capture = {
+		.stream_name = "Capture",
+		.channels_min = 2,
+		.channels_max = 8,
+		.rates = SNDRV_PCM_RATE_32000 |
+			 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |
+			 SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 |
+			 SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
+		.formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+	},
+
+	.ops = &cdn_dp_audio_dai_ops,
+};
+
+static const struct snd_soc_codec_driver cdn_dp_audio = {
+	.dapm_widgets = snd_cdn_dp_audio_widgets,
+	.num_dapm_widgets = ARRAY_SIZE(snd_cdn_dp_audio_widgets),
+	.dapm_routes = snd_cdn_dp_audio_routes,
+	.num_dapm_routes = ARRAY_SIZE(snd_cdn_dp_audio_routes),
+};
+
+static int cdn_dp_audio_probe(struct platform_device *pdev)
+{
+	struct cdn_dp_audio_pdata *pdata = pdev->dev.platform_data;
+	struct snd_cdn_dp_audio *ad;
+	int ret;
+
+	ad = devm_kzalloc(&pdev->dev, sizeof(*ad), GFP_KERNEL);
+	if (!ad)
+		return -ENOMEM;
+
+	ad->dev = pdata->dev;
+	ad->ops = pdata->ops;
+	ad->data = pdata->data;
+
+	platform_set_drvdata(pdev, ad);
+
+	ret = snd_soc_register_codec(&pdev->dev, &cdn_dp_audio,
+				     &cdn_dp_audio_dai, 1);
+	if (ret) {
+		dev_err(&pdev->dev, "register codec failed (%d)\n", ret);
+		return ret;
+	}
+
+	return 0;
+}
+
+static int cdn_dp_audio_remove(struct platform_device *pdev)
+{
+	snd_soc_unregister_codec(&pdev->dev);
+
+	return 0;
+}
+
+static const struct of_device_id cdn_dp_audio_ids[] = {
+	{ .compatible = "cdn-dp-audio", },
+	{ }
+};
+
+static struct platform_driver cdn_dp_audio_driver = {
+	.driver = {
+		.name = "cdn-dp-audio",
+		.owner = THIS_MODULE,
+		.of_match_table = of_match_ptr(cdn_dp_audio_ids),
+	},
+	.probe = cdn_dp_audio_probe,
+	.remove = cdn_dp_audio_remove,
+};
+module_platform_driver(cdn_dp_audio_driver);
+
+MODULE_AUTHOR("Chris Zhong <zyw at rock-chips.com>");
+MODULE_DESCRIPTION("CDN DP Audio ASoC Interface");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform: cdn-dp-audio");
+MODULE_DEVICE_TABLE(of, cdn_dp_audio_ids);
-- 
2.6.3



From william.wu at rock-chips.com  Fri May 27 04:28:04 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 27 May 2016 19:28:04 +0800
Subject: [PATCH v3 1/5] usb: dwc3: of-simple: add compatible for rockchip
In-Reply-To: <1464348488-20760-1-git-send-email-william.wu@rock-chips.com>
References: <1464348488-20760-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <1464348488-20760-2-git-send-email-william.wu@rock-chips.com>

Rockchip platform merely enable usb3 clocks and
populate its children. So we can use this generic
glue layer to support Rockchip dwc3.

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v3:
- None

Changes in v2:
- sort the list of_dwc3_simple_match (Doug)

 drivers/usb/dwc3/dwc3-of-simple.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/drivers/usb/dwc3/dwc3-of-simple.c b/drivers/usb/dwc3/dwc3-of-simple.c
index 9743353..6da9656 100644
--- a/drivers/usb/dwc3/dwc3-of-simple.c
+++ b/drivers/usb/dwc3/dwc3-of-simple.c
@@ -161,6 +161,7 @@ static const struct dev_pm_ops dwc3_of_simple_dev_pm_ops = {
 
 static const struct of_device_id of_dwc3_simple_match[] = {
 	{ .compatible = "qcom,dwc3" },
+	{ .compatible = "rockchip,dwc3" },
 	{ .compatible = "xlnx,zynqmp-dwc3" },
 	{ /* Sentinel */ }
 };
-- 
1.9.1




From william.wu at rock-chips.com  Fri May 27 04:28:05 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 27 May 2016 19:28:05 +0800
Subject: [PATCH v3 2/5] usb: dwc3: add dis_u2_freeclk_exists_quirk
In-Reply-To: <1464348488-20760-1-git-send-email-william.wu@rock-chips.com>
References: <1464348488-20760-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <1464348488-20760-3-git-send-email-william.wu@rock-chips.com>

Add a quirk to clear the GUSB2PHYCFG.U2_FREECLK_EXISTS bit,
which specifies whether the USB2.0 PHY provides a free-running
PHY clock, which is active when the clock control input is active.

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v3:
- None

Changes in v2:
- None

 Documentation/devicetree/bindings/usb/dwc3.txt | 3 +++
 drivers/usb/dwc3/core.c                        | 7 +++++++
 drivers/usb/dwc3/core.h                        | 5 +++++
 drivers/usb/dwc3/platform_data.h               | 1 +
 4 files changed, 16 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 7d7ce08..1ada121 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -39,6 +39,9 @@ Optional properties:
 			disabling the suspend signal to the PHY.
  - snps,dis_rxdet_inp3_quirk: when set core will disable receiver detection
 			in PHY P3 power state.
+ - snps,dis_u2_freeclk_exists_quirk: when set, clear the u2_freeclk_exists
+			in GUSB2PHYCFG, specify that USB2 PHY doesn't provide
+			a free-running PHY clock.
  - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
 			utmi_l1_suspend_n, false when asserts utmi_sleep_n
  - snps,hird-threshold: HIRD threshold
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index a590cd2..8bcd3cc 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -502,6 +502,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
 	if (dwc->dis_enblslpm_quirk)
 		reg &= ~DWC3_GUSB2PHYCFG_ENBLSLPM;
 
+	if (dwc->dis_u2_freeclk_exists_quirk)
+		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
+
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
 	return 0;
@@ -901,6 +904,8 @@ static int dwc3_probe(struct platform_device *pdev)
 				"snps,dis_enblslpm_quirk");
 	dwc->dis_rxdet_inp3_quirk = device_property_read_bool(dev,
 				"snps,dis_rxdet_inp3_quirk");
+	dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
+				"snps,dis_u2_freeclk_exists_quirk");
 
 	dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
 				"snps,tx_de_emphasis_quirk");
@@ -935,6 +940,8 @@ static int dwc3_probe(struct platform_device *pdev)
 		dwc->dis_u2_susphy_quirk = pdata->dis_u2_susphy_quirk;
 		dwc->dis_enblslpm_quirk = pdata->dis_enblslpm_quirk;
 		dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk;
+		dwc->dis_u2_freeclk_exists_quirk =
+					pdata->dis_u2_freeclk_exists_quirk;
 
 		dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
 		if (pdata->tx_de_emphasis)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index 7ddf944..ac2e6b5 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -196,6 +196,7 @@
 
 /* Global USB2 PHY Configuration Register */
 #define DWC3_GUSB2PHYCFG_PHYSOFTRST	(1 << 31)
+#define	DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS	(1 << 30)
 #define DWC3_GUSB2PHYCFG_SUSPHY		(1 << 6)
 #define DWC3_GUSB2PHYCFG_ULPI_UTMI	(1 << 4)
 #define DWC3_GUSB2PHYCFG_ENBLSLPM	(1 << 8)
@@ -770,6 +771,9 @@ struct dwc3_scratchpad_array {
  * @dis_u2_susphy_quirk: set if we disable usb2 suspend phy
  * @dis_enblslpm_quirk: set if we clear enblslpm in GUSB2PHYCFG,
  *                      disabling the suspend signal to the PHY.
+ * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
+ *			in GUSB2PHYCFG, specify that USB2 PHY doesn't
+ *			provide a free-running PHY clock.
  * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
  * @tx_de_emphasis: Tx de-emphasis value
  * 	0	- -6dB de-emphasis
@@ -913,6 +917,7 @@ struct dwc3 {
 	unsigned		dis_u2_susphy_quirk:1;
 	unsigned		dis_enblslpm_quirk:1;
 	unsigned		dis_rxdet_inp3_quirk:1;
+	unsigned		dis_u2_freeclk_exists_quirk:1;
 
 	unsigned		tx_de_emphasis_quirk:1;
 	unsigned		tx_de_emphasis:2;
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
index 8826cca..e1a1631 100644
--- a/drivers/usb/dwc3/platform_data.h
+++ b/drivers/usb/dwc3/platform_data.h
@@ -43,6 +43,7 @@ struct dwc3_platform_data {
 	unsigned dis_u2_susphy_quirk:1;
 	unsigned dis_enblslpm_quirk:1;
 	unsigned dis_rxdet_inp3_quirk:1;
+	unsigned dis_u2_freeclk_exists_quirk:1;
 
 	unsigned tx_de_emphasis_quirk:1;
 	unsigned tx_de_emphasis:2;
-- 
1.9.1




From william.wu at rock-chips.com  Fri May 27 04:28:06 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 27 May 2016 19:28:06 +0800
Subject: [PATCH v3 3/5] usb: dwc3: add phyif_utmi_quirk
In-Reply-To: <1464348488-20760-1-git-send-email-william.wu@rock-chips.com>
References: <1464348488-20760-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <1464348488-20760-4-git-send-email-william.wu@rock-chips.com>

Add a quirk to configure the core to support the
UTMI+ PHY with an 8- or 16-bit interface. UTMI+ PHY
interface is hardware property, and it's platform
dependent. Normall, the PHYIf can be configured
during coreconsultant. But for some specific usb
cores(e.g. rk3399 soc dwc3), the default PHYIf
configuration value is fault, so we need to
reconfigure it by software.

And refer to the dwc3 databook, the GUSB2PHYCFG.USBTRDTIM
must be set to the corresponding value according to
the UTMI+ PHY interface.

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v3:
- None

Changes in v2:
- add a quirk for phyif_utmi (Felipe)

 Documentation/devicetree/bindings/usb/dwc3.txt |  4 ++++
 drivers/usb/dwc3/core.c                        | 23 +++++++++++++++++++++++
 drivers/usb/dwc3/core.h                        | 12 ++++++++++++
 drivers/usb/dwc3/platform_data.h               |  2 ++
 4 files changed, 41 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 1ada121..34d13a5 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -42,6 +42,10 @@ Optional properties:
  - snps,dis_u2_freeclk_exists_quirk: when set, clear the u2_freeclk_exists
 			in GUSB2PHYCFG, specify that USB2 PHY doesn't provide
 			a free-running PHY clock.
+ - snps,phyif_utmi_quirk: when set core will set phyif UTMI+ interface.
+ - snps,phyif_utmi: the value to configure the core to support a UTMI+ PHY
+			with an 8- or 16-bit interface. Value 0 select 8-bit
+			interface, value 1 select 16-bit interface.
  - snps,is-utmi-l1-suspend: true when DWC3 asserts output signal
 			utmi_l1_suspend_n, false when asserts utmi_sleep_n
  - snps,hird-threshold: HIRD threshold
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index 8bcd3cc..d99c170 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -410,6 +410,7 @@ static void dwc3_cache_hwparams(struct dwc3 *dwc)
 static int dwc3_phy_setup(struct dwc3 *dwc)
 {
 	u32 reg;
+	u32 usbtrdtim;
 	int ret;
 
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB3PIPECTL(0));
@@ -505,6 +506,15 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
 	if (dwc->dis_u2_freeclk_exists_quirk)
 		reg &= ~DWC3_GUSB2PHYCFG_U2_FREECLK_EXISTS;
 
+	if (dwc->phyif_utmi_quirk) {
+		reg &= ~(DWC3_GUSB2PHYCFG_PHYIF_MASK |
+		       DWC3_GUSB2PHYCFG_USBTRDTIM_MASK);
+		usbtrdtim = dwc->phyif_utmi ? USBTRDTIM_UTMI_16_BIT :
+			    USBTRDTIM_UTMI_8_BIT;
+		reg |= DWC3_GUSB2PHYCFG_PHYIF(dwc->phyif_utmi) |
+		       DWC3_GUSB2PHYCFG_USBTRDTIM(usbtrdtim);
+	}
+
 	dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
 
 	return 0;
@@ -800,6 +810,7 @@ static int dwc3_probe(struct platform_device *pdev)
 	struct resource		*res;
 	struct dwc3		*dwc;
 	u8			lpm_nyet_threshold;
+	u8			phyif_utmi;
 	u8			tx_de_emphasis;
 	u8			hird_threshold;
 	u32			fladj = 0;
@@ -857,6 +868,9 @@ static int dwc3_probe(struct platform_device *pdev)
 	/* default to highest possible threshold */
 	lpm_nyet_threshold = 0xff;
 
+	/* default to UTMI+ 8-bit interface */
+	phyif_utmi = 0;
+
 	/* default to -3.5dB de-emphasis */
 	tx_de_emphasis = 1;
 
@@ -907,6 +921,10 @@ static int dwc3_probe(struct platform_device *pdev)
 	dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
 				"snps,dis_u2_freeclk_exists_quirk");
 
+	dwc->phyif_utmi_quirk = device_property_read_bool(dev,
+				"snps,phyif_utmi_quirk");
+	device_property_read_u8(dev, "snps,phyif_utmi",
+				&phyif_utmi);
 	dwc->tx_de_emphasis_quirk = device_property_read_bool(dev,
 				"snps,tx_de_emphasis_quirk");
 	device_property_read_u8(dev, "snps,tx_de_emphasis",
@@ -943,6 +961,10 @@ static int dwc3_probe(struct platform_device *pdev)
 		dwc->dis_u2_freeclk_exists_quirk =
 					pdata->dis_u2_freeclk_exists_quirk;
 
+		dwc->phyif_utmi_quirk = pdata->phyif_utmi_quirk;
+		if (pdata->phyif_utmi)
+			phyif_utmi = pdata->phyif_utmi;
+
 		dwc->tx_de_emphasis_quirk = pdata->tx_de_emphasis_quirk;
 		if (pdata->tx_de_emphasis)
 			tx_de_emphasis = pdata->tx_de_emphasis;
@@ -952,6 +974,7 @@ static int dwc3_probe(struct platform_device *pdev)
 	}
 
 	dwc->lpm_nyet_threshold = lpm_nyet_threshold;
+	dwc->phyif_utmi = phyif_utmi;
 	dwc->tx_de_emphasis = tx_de_emphasis;
 
 	dwc->hird_threshold = hird_threshold
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index ac2e6b5..e1fcae8 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -200,6 +200,12 @@
 #define DWC3_GUSB2PHYCFG_SUSPHY		(1 << 6)
 #define DWC3_GUSB2PHYCFG_ULPI_UTMI	(1 << 4)
 #define DWC3_GUSB2PHYCFG_ENBLSLPM	(1 << 8)
+#define DWC3_GUSB2PHYCFG_PHYIF(n)	(n << 3)
+#define DWC3_GUSB2PHYCFG_PHYIF_MASK	DWC3_GUSB2PHYCFG_PHYIF(1)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM(n)	(n << 10)
+#define DWC3_GUSB2PHYCFG_USBTRDTIM_MASK	DWC3_GUSB2PHYCFG_USBTRDTIM(0xf)
+#define USBTRDTIM_UTMI_8_BIT		9
+#define USBTRDTIM_UTMI_16_BIT		5
 
 /* Global USB2 PHY Vendor Control Register */
 #define DWC3_GUSB2PHYACC_NEWREGREQ	(1 << 25)
@@ -774,6 +780,10 @@ struct dwc3_scratchpad_array {
  * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
  *			in GUSB2PHYCFG, specify that USB2 PHY doesn't
  *			provide a free-running PHY clock.
+ * @phyif_utmi_quirk: set if we enable phyif UTMI+ quirk
+ * @phyif_utmi: UTMI+ PHY interface value
+ *	0	- 8 bits
+ *	1	- 16 bits
  * @tx_de_emphasis_quirk: set if we enable Tx de-emphasis quirk
  * @tx_de_emphasis: Tx de-emphasis value
  * 	0	- -6dB de-emphasis
@@ -919,6 +929,8 @@ struct dwc3 {
 	unsigned		dis_rxdet_inp3_quirk:1;
 	unsigned		dis_u2_freeclk_exists_quirk:1;
 
+	unsigned		phyif_utmi_quirk:1;
+	unsigned		phyif_utmi:1;
 	unsigned		tx_de_emphasis_quirk:1;
 	unsigned		tx_de_emphasis:2;
 };
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
index e1a1631..b521565 100644
--- a/drivers/usb/dwc3/platform_data.h
+++ b/drivers/usb/dwc3/platform_data.h
@@ -45,6 +45,8 @@ struct dwc3_platform_data {
 	unsigned dis_rxdet_inp3_quirk:1;
 	unsigned dis_u2_freeclk_exists_quirk:1;
 
+	unsigned phyif_utmi_quirk:1;
+	unsigned phyif_utmi:1;
 	unsigned tx_de_emphasis_quirk:1;
 	unsigned tx_de_emphasis:2;
 
-- 
1.9.1




From william.wu at rock-chips.com  Fri May 27 04:28:03 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 27 May 2016 19:28:03 +0800
Subject: [PATCH v3 0/5] support rockchip dwc3 driver
Message-ID: <1464348488-20760-1-git-send-email-william.wu@rock-chips.com>

This series add support for rockchip dwc3 driver,
and add additional optional properties for specific
platforms (e.g., rockchip platform).

William Wu (5):
  usb: dwc3: of-simple: add compatible for rockchip
  usb: dwc3: add dis_u2_freeclk_exists_quirk
  usb: dwc3: add phyif_utmi_quirk
  usb: dwc3: add dis_del_phy_power_chg_quirk
  usb: dwc3: rockchip: add devicetree bindings documentation

 Documentation/devicetree/bindings/usb/dwc3.txt     |  9 +++++
 .../devicetree/bindings/usb/rockchip,dwc3.txt      | 45 ++++++++++++++++++++++
 drivers/usb/dwc3/core.c                            | 39 ++++++++++++++++++-
 drivers/usb/dwc3/core.h                            | 20 ++++++++++
 drivers/usb/dwc3/dwc3-of-simple.c                  |  1 +
 drivers/usb/dwc3/platform_data.h                   |  4 ++
 6 files changed, 117 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt

-- 
1.9.1




From william.wu at rock-chips.com  Fri May 27 04:28:07 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 27 May 2016 19:28:07 +0800
Subject: [PATCH v3 4/5] usb: dwc3: add dis_del_phy_power_chg_quirk
In-Reply-To: <1464348488-20760-1-git-send-email-william.wu@rock-chips.com>
References: <1464348488-20760-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <1464348488-20760-5-git-send-email-william.wu@rock-chips.com>

Add a quirk to clear the GUSB3PIPECTL.DELAYP1TRANS bit,
which specifies whether disable delay PHY power change
from P0 to P1/P2/P3 when link state changing from U0
to U1/U2/U3 respectively.

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v3:
- None

Changes in v2:
- None

 Documentation/devicetree/bindings/usb/dwc3.txt | 2 ++
 drivers/usb/dwc3/core.c                        | 7 +++++++
 drivers/usb/dwc3/core.h                        | 3 +++
 drivers/usb/dwc3/platform_data.h               | 1 +
 4 files changed, 13 insertions(+)

diff --git a/Documentation/devicetree/bindings/usb/dwc3.txt b/Documentation/devicetree/bindings/usb/dwc3.txt
index 34d13a5..bd5bef0 100644
--- a/Documentation/devicetree/bindings/usb/dwc3.txt
+++ b/Documentation/devicetree/bindings/usb/dwc3.txt
@@ -42,6 +42,8 @@ Optional properties:
  - snps,dis_u2_freeclk_exists_quirk: when set, clear the u2_freeclk_exists
 			in GUSB2PHYCFG, specify that USB2 PHY doesn't provide
 			a free-running PHY clock.
+ - snps,dis_del_phy_power_chg_quirk: when set core will change PHY power
+			from P0 to P1/P2/P3 without delay.
  - snps,phyif_utmi_quirk: when set core will set phyif UTMI+ interface.
  - snps,phyif_utmi: the value to configure the core to support a UTMI+ PHY
 			with an 8- or 16-bit interface. Value 0 select 8-bit
diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c
index d99c170..c06870c 100644
--- a/drivers/usb/dwc3/core.c
+++ b/drivers/usb/dwc3/core.c
@@ -451,6 +451,9 @@ static int dwc3_phy_setup(struct dwc3 *dwc)
 	if (dwc->dis_u3_susphy_quirk)
 		reg &= ~DWC3_GUSB3PIPECTL_SUSPHY;
 
+	if (dwc->dis_del_phy_power_chg_quirk)
+		reg &= ~DWC3_GUSB3PIPECTL_DEPOCHANGE;
+
 	dwc3_writel(dwc->regs, DWC3_GUSB3PIPECTL(0), reg);
 
 	reg = dwc3_readl(dwc->regs, DWC3_GUSB2PHYCFG(0));
@@ -920,6 +923,8 @@ static int dwc3_probe(struct platform_device *pdev)
 				"snps,dis_rxdet_inp3_quirk");
 	dwc->dis_u2_freeclk_exists_quirk = device_property_read_bool(dev,
 				"snps,dis_u2_freeclk_exists_quirk");
+	dwc->dis_del_phy_power_chg_quirk = device_property_read_bool(dev,
+				"snps,dis_del_phy_power_chg_quirk");
 
 	dwc->phyif_utmi_quirk = device_property_read_bool(dev,
 				"snps,phyif_utmi_quirk");
@@ -960,6 +965,8 @@ static int dwc3_probe(struct platform_device *pdev)
 		dwc->dis_rxdet_inp3_quirk = pdata->dis_rxdet_inp3_quirk;
 		dwc->dis_u2_freeclk_exists_quirk =
 					pdata->dis_u2_freeclk_exists_quirk;
+		dwc->dis_del_phy_power_chg_quirk =
+					pdata->dis_del_phy_power_chg_quirk;
 
 		dwc->phyif_utmi_quirk = pdata->phyif_utmi_quirk;
 		if (pdata->phyif_utmi)
diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h
index e1fcae8..abed84f 100644
--- a/drivers/usb/dwc3/core.h
+++ b/drivers/usb/dwc3/core.h
@@ -780,6 +780,8 @@ struct dwc3_scratchpad_array {
  * @dis_u2_freeclk_exists_quirk : set if we clear u2_freeclk_exists
  *			in GUSB2PHYCFG, specify that USB2 PHY doesn't
  *			provide a free-running PHY clock.
+ * @dis_del_phy_power_chg_quirk: set if we disable delay phy power
+ *			change quirk.
  * @phyif_utmi_quirk: set if we enable phyif UTMI+ quirk
  * @phyif_utmi: UTMI+ PHY interface value
  *	0	- 8 bits
@@ -928,6 +930,7 @@ struct dwc3 {
 	unsigned		dis_enblslpm_quirk:1;
 	unsigned		dis_rxdet_inp3_quirk:1;
 	unsigned		dis_u2_freeclk_exists_quirk:1;
+	unsigned		dis_del_phy_power_chg_quirk:1;
 
 	unsigned		phyif_utmi_quirk:1;
 	unsigned		phyif_utmi:1;
diff --git a/drivers/usb/dwc3/platform_data.h b/drivers/usb/dwc3/platform_data.h
index b521565..ab45d91 100644
--- a/drivers/usb/dwc3/platform_data.h
+++ b/drivers/usb/dwc3/platform_data.h
@@ -44,6 +44,7 @@ struct dwc3_platform_data {
 	unsigned dis_enblslpm_quirk:1;
 	unsigned dis_rxdet_inp3_quirk:1;
 	unsigned dis_u2_freeclk_exists_quirk:1;
+	unsigned dis_del_phy_power_chg_quirk:1;
 
 	unsigned phyif_utmi_quirk:1;
 	unsigned phyif_utmi:1;
-- 
1.9.1




From william.wu at rock-chips.com  Fri May 27 04:31:22 2016
From: william.wu at rock-chips.com (William Wu)
Date: Fri, 27 May 2016 19:31:22 +0800
Subject: [PATCH v3 5/5] usb: dwc3: rockchip: add devicetree bindings
 documentation
Message-ID: <1464348682-20831-1-git-send-email-william.wu@rock-chips.com>

This patch documents the device tree documentation required for
Rockchip USB3.0 core wrapper consist of USB3.0 IP from Synopsys.

It could operate in device mode (SS, HS, FS) and host
mode (SS, HS, FS, LS).

Signed-off-by: William Wu <william.wu at rock-chips.com>
---
Changes in v3:
- add dwc3 address (Felipe)

Changes in v2:
- add rockchip,dwc3.txt to Documentation/devicetree/bindings/ (Felipe, Brian)


 .../devicetree/bindings/usb/rockchip,dwc3.txt      | 45 ++++++++++++++++++++++
 1 file changed, 45 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt

diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
new file mode 100644
index 0000000..0bb52fe
--- /dev/null
+++ b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
@@ -0,0 +1,45 @@
+Rockchip SuperSpeed DWC3 USB SoC controller
+
+Required properties:
+- compatible:	should contain "rockchip,dwc3"
+- clocks:		A list of phandle + clock-specifier pairs for the
+				clocks listed in clock-names
+- clock-names:	Should contain the following:
+  "clk_usb3otg0_ref"	Controller reference clk
+  "clk_usb3otg0_suspend"Controller suspend clk, can use 24 MHz or 32 KHz
+  "aclk_usb3"		Master/Core clock, have to be >= 62.5 MHz for SS operation
+
+
+Optional clocks:
+  "aclk_usb3otg0"	Aclk for specific usb controller clock.
+  "aclk_usb3_rksoc_axi_perf"  USB AXI perf clock.  Not present on all platforms.
+  "aclk_usb3_grf"	USB grf clock.  Not present on all platforms.
+
+Required child node:
+A child node must exist to represent the core DWC3 IP block. The name of
+the node is not important. The content of the node is defined in dwc3.txt.
+
+Phy documentation is provided in the following places:
+
+Example device nodes:
+
+	usbdrd3_0: usb at fe800000 {
+		compatible = "rockchip,dwc3";
+		clocks = <&cru SCLK_USB3OTG0_REF>, <&cru SCLK_USB3OTG0_SUSPEND>,
+			 <&cru ACLK_USB3>, <&cru ACLK_USB3OTG0>,
+			 <&cru ACLK_USB3_RKSOC_AXI_PERF>, <&cru ACLK_USB3_GRF>;
+		clock-names = "clk_usb3otg0_ref", "clk_usb3otg0_suspend",
+			      "aclk_usb3", "aclk_usb3otg0",
+			      "aclk_usb3_rksoc_axi_perf", "aclk_usb3_grf";
+		#address-cells = <2>;
+		#size-cells = <2>;
+		ranges;
+		status = "disabled";
+		usbdrd_dwc3_0: dwc3 at fe800000 {
+			compatible = "snps,dwc3";
+			reg = <0x0 0xfe800000 0x0 0x100000>;
+			interrupts = <GIC_SPI 105 IRQ_TYPE_LEVEL_HIGH>;
+			dr_mode = "otg";
+			status = "disabled";
+		};
+	};
-- 
1.9.1




From sergei.shtylyov at cogentembedded.com  Fri May 27 04:54:16 2016
From: sergei.shtylyov at cogentembedded.com (Sergei Shtylyov)
Date: Fri, 27 May 2016 14:54:16 +0300
Subject: [PATCH v3 5/5] usb: dwc3: rockchip: add devicetree bindings
 documentation
In-Reply-To: <1464348682-20831-1-git-send-email-william.wu@rock-chips.com>
References: <1464348682-20831-1-git-send-email-william.wu@rock-chips.com>
Message-ID: <e6c6407c-6a46-55c8-c048-cce4fc0e7fa8@cogentembedded.com>

Hello.

On 5/27/2016 2:31 PM, William Wu wrote:

> This patch documents the device tree documentation required for

    Documents the documentation? :-)

> Rockchip USB3.0 core wrapper consist of USB3.0 IP from Synopsys.

    Consisting?

> It could operate in device mode (SS, HS, FS) and host
> mode (SS, HS, FS, LS).
>
> Signed-off-by: William Wu <william.wu at rock-chips.com>
> ---
> Changes in v3:
> - add dwc3 address (Felipe)
>
> Changes in v2:
> - add rockchip,dwc3.txt to Documentation/devicetree/bindings/ (Felipe, Brian)
>
>
>  .../devicetree/bindings/usb/rockchip,dwc3.txt      | 45 ++++++++++++++++++++++
>  1 file changed, 45 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
>
> diff --git a/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
> new file mode 100644
> index 0000000..0bb52fe
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/usb/rockchip,dwc3.txt
> @@ -0,0 +1,45 @@
> +Rockchip SuperSpeed DWC3 USB SoC controller
> +
> +Required properties:
> +- compatible:	should contain "rockchip,dwc3"
> +- clocks:		A list of phandle + clock-specifier pairs for the
> +				clocks listed in clock-names
> +- clock-names:	Should contain the following:
> +  "clk_usb3otg0_ref"	Controller reference clk
> +  "clk_usb3otg0_suspend"Controller suspend clk, can use 24 MHz or 32 KHz
> +  "aclk_usb3"		Master/Core clock, have to be >= 62.5 MHz for SS operation
> +
> +
> +Optional clocks:
> +  "aclk_usb3otg0"	Aclk for specific usb controller clock.
> +  "aclk_usb3_rksoc_axi_perf"  USB AXI perf clock.  Not present on all platforms.
> +  "aclk_usb3_grf"	USB grf clock.  Not present on all platforms.
> +
> +Required child node:
> +A child node must exist to represent the core DWC3 IP block. The name of
> +the node is not important. The content of the node is defined in dwc3.txt.
> +
> +Phy documentation is provided in the following places:

    PHY.

[...]

MBR, Sergei



From marc.zyngier at arm.com  Fri May 27 05:25:14 2016
From: marc.zyngier at arm.com (Marc Zyngier)
Date: Fri, 27 May 2016 13:25:14 +0100
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <57483CAA.8000005@arm.com>

[+Lorenzo]

On 20/05/16 11:29, Shawn Lin wrote:
> RK3399 has a PCIe controller which can be used as Root Complex.
> This driver supports a PCIe controller as Root Complex mode.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> ---
> 
>  drivers/pci/host/Kconfig         |   12 +
>  drivers/pci/host/Makefile        |    1 +
>  drivers/pci/host/pcie-rockchip.c | 1181 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 1194 insertions(+)
>  create mode 100644 drivers/pci/host/pcie-rockchip.c
> 
> diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
> index 8e4f038..76447a8 100644
> --- a/drivers/pci/host/Kconfig
> +++ b/drivers/pci/host/Kconfig
> @@ -245,4 +245,16 @@ config PCIE_ARMADA_8K
>  	  Designware hardware and therefore the driver re-uses the
>  	  Designware core functions to implement the driver.
>  
> +config PCIE_ROCKCHIP
> +	bool "Rockchip PCIe controller"
> +	depends on ARM64 && ARCH_ROCKCHIP
> +	depends on OF
> +	select MFD_SYSCON
> +	select PCI_MSI
> +	select PCI_MSI_IRQ_DOMAIN
> +	help
> +	  Say Y here if you want internal PCI support on Rockchip SoC.
> +	  There are 1 internal PCIe port available to support GEN2 with
> +	  4 slots.
> +
>  endmenu
> diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
> index a6f85e3..fb3871e 100644
> --- a/drivers/pci/host/Makefile
> +++ b/drivers/pci/host/Makefile
> @@ -29,3 +29,4 @@ obj-$(CONFIG_PCIE_QCOM) += pcie-qcom.o
>  obj-$(CONFIG_PCI_HOST_THUNDER_ECAM) += pci-thunder-ecam.o
>  obj-$(CONFIG_PCI_HOST_THUNDER_PEM) += pci-thunder-pem.o
>  obj-$(CONFIG_PCIE_ARMADA_8K) += pcie-armada8k.o
> +obj-$(CONFIG_PCIE_ROCKCHIP) += pcie-rockchip.o
> diff --git a/drivers/pci/host/pcie-rockchip.c b/drivers/pci/host/pcie-rockchip.c
> new file mode 100644
> index 0000000..4063fd3
> --- /dev/null
> +++ b/drivers/pci/host/pcie-rockchip.c
> @@ -0,0 +1,1181 @@
> +/*
> + * Rockchip AXI PCIe host controller driver
> + *
> + * Copyright (c) 2016 Rockchip, Inc.
> + *
> + * Author: Shawn Lin <shawn.lin at rock-chips.com>
> + *         Wenrui Li <wenrui.li at rock-chips.com>
> + * Bits taken from Synopsys Designware Host controller driver and
> + * ARM PCI Host generic driver.
> + *
> + * This program is free software: you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation, either version 2 of the License, or
> + * (at your option) any later version.
> + */
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/gpio/consumer.h>
> +#include <linux/interrupt.h>
> +#include <linux/irq.h>
> +#include <linux/irqdomain.h>
> +#include <linux/kernel.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/msi.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/of_pci.h>
> +#include <linux/of_platform.h>
> +#include <linux/of_irq.h>
> +#include <linux/pci.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +#include <linux/regmap.h>
> +
> +#define REF_CLK_100MHZ			(100 * 1000 * 1000)
> +#define PCIE_CLIENT_BASE		0x0
> +#define PCIE_RC_CONFIG_BASE		0xa00000
> +#define PCIE_CORE_CTRL_MGMT_BASE	0x900000
> +#define PCIE_CORE_AXI_CONF_BASE		0xc00000
> +#define PCIE_CORE_AXI_INBOUND_BASE	0xc00800
> +
> +#define PCIE_CLIENT_BASIC_STATUS0	0x44
> +#define PCIE_CLIENT_BASIC_STATUS1	0x48
> +#define PCIE_CLIENT_INT_MASK		0x4c
> +#define PCIE_CLIENT_INT_STATUS		0x50
> +#define PCIE_CORE_INT_MASK		0x900210
> +#define PCIE_CORE_INT_STATUS		0x90020c
> +
> +/** Size of one AXI Region (not Region 0) */
> +#define	AXI_REGION_SIZE			(0x1 << 20)
> +/** Overall size of AXI area */
> +#define	AXI_OVERALL_SIZE		(64 * (0x1 << 20))
> +/** Size of Region 0, equal to sum of sizes of other regions */
> +#define	AXI_REGION_0_SIZE		(32 * (0x1 << 20))
> +#define OB_REG_SIZE_SHIFT		5
> +#define IB_ROOT_PORT_REG_SIZE_SHIFT	3
> +
> +#define AXI_WRAPPER_IO_WRITE		0x6
> +#define AXI_WRAPPER_MEM_WRITE		0x2
> +#define MAX_AXI_IB_ROOTPORT_REGION_NUM	3
> +#define	MIN_AXI_ADDR_BITS_PASSED	8
> +
> +#define ROCKCHIP_PCIE_RPIFR1_INTR_MASK	GENMASK(8, 5)
> +#define ROCKCHIP_PCIE_RPIFR1_INTR_SHIFT	5
> +#define CLIENT_INTERRUPTS \
> +		(LOC_INT | INTA | INTB | INTC | INTD |\
> +		 CORR_ERR | NFATAL_ERR | FATAL_ERR | DPA_INT | \
> +		 HOT_RESET | MSG_DONE | LEGACY_DONE)
> +#define CORE_INTERRUPTS	\
> +		(PRFPE | CRFPE | RRPE | CRFO | RT | RTR | \
> +		 PE | MTR | UCR | FCE | CT | UTC | MMVC)
> +#define PWR_STCG			BIT(0)
> +#define HOT_PLUG			BIT(1)
> +#define PHY_INT				BIT(2)
> +#define UDMA_INT			BIT(3)
> +#define LOC_INT				BIT(4)
> +#define INTA				BIT(5)
> +#define INTB				BIT(6)
> +#define INTC				BIT(7)
> +#define INTD				BIT(8)
> +#define CORR_ERR			BIT(9)
> +#define NFATAL_ERR			BIT(10)
> +#define FATAL_ERR			BIT(11)
> +#define DPA_INT				BIT(12)
> +#define HOT_RESET			BIT(13)
> +#define MSG_DONE			BIT(14)
> +#define LEGACY_DONE			BIT(15)
> +#define PRFPE				BIT(0)
> +#define CRFPE				BIT(1)
> +#define RRPE				BIT(2)
> +#define PRFO				BIT(3)
> +#define CRFO				BIT(4)
> +#define RT				BIT(5)
> +#define RTR				BIT(6)
> +#define PE				BIT(7)
> +#define MTR				BIT(8)
> +#define UCR				BIT(9)
> +#define FCE				BIT(10)
> +#define CT				BIT(11)
> +#define UTC				BIT(18)
> +#define MMVC				BIT(19)
> +
> +#define PCIE_ECAM_BUS(x)		(((x) & 0xFF) << 20)
> +#define PCIE_ECAM_DEV(x)		(((x) & 0x1F) << 15)
> +#define PCIE_ECAM_FUNC(x)		(((x) & 0x7) << 12)
> +#define PCIE_ECAM_REG(x)		(((x) & 0xFFF) << 0)
> +#define PCIE_ECAM_ADDR(bus, dev, func, reg) \
> +	  (PCIE_ECAM_BUS(bus) | PCIE_ECAM_DEV(dev) | \
> +	   PCIE_ECAM_FUNC(func) | PCIE_ECAM_REG(reg))
> +
> +#define RC_REGION_0_ADDR_TRANS_H	0x00000000
> +#define RC_REGION_0_ADDR_TRANS_L	0x00000000
> +#define RC_REGION_0_PASS_BITS		(25 - 1)
> +#define RC_REGION_1_ADDR_TRANS_H	0x00000000
> +#define RC_REGION_1_ADDR_TRANS_L	0x00400000
> +#define RC_REGION_1_PASS_BITS		(20 - 1)
> +#define MAX_AXI_WRAPPER_REGION_NUM	33
> +#define PCIE_CLIENT_CONF_ENABLE		BIT(0)
> +#define PCIE_CLIENT_CONF_LANE_NUM(x)	((x / 2) << 4)
> +#define PCIE_CLIENT_MODE_RC		BIT(6)
> +#define PCIE_CLIENT_GEN_SEL_2		BIT(7)
> +#define PCIE_CLIENT_GEN_SEL_1		0x0
> +
> +struct rockchip_pcie_port {
> +	void __iomem *reg_base;
> +	void __iomem *apb_base;
> +	struct regmap *grf;
> +	unsigned int pcie_conf;
> +	unsigned int pcie_status;
> +	unsigned int pcie_laneoff;
> +	struct reset_control *phy_rst;
> +	struct reset_control *core_rst;
> +	struct reset_control *mgmt_rst;
> +	struct reset_control *mgmt_sticky_rst;
> +	struct reset_control *pipe_rst;
> +	struct clk *aclk_pcie;
> +	struct clk *aclk_perf_pcie;
> +	struct clk *hclk_pcie;
> +	struct clk *clk_pciephy_ref;
> +	struct gpio_desc *ep_gpio;
> +	u32 lanes;
> +	resource_size_t		io_base;
> +	struct resource		*cfg;
> +	struct resource		*io;
> +	struct resource		*mem;
> +	struct resource		*busn;
> +	phys_addr_t		io_bus_addr;
> +	u32			io_size;
> +	phys_addr_t		mem_bus_addr;
> +	u32			mem_size;
> +	u8	root_bus_nr;
> +	int irq;
> +	struct msi_controller *msi;

Don't. struct msi_controller shouldn't be used in new code, and
certainly not for an arm64 system.

But even worse: your SoC seems to use a GICv3 ITS. Great. Which means
you do not need any of that at all.

> +
> +	struct device *dev;
> +	struct irq_domain *irq_domain;
> +};

[...]


> +static void rockchip_pcie_msi_enable(struct rockchip_pcie_port *pp)
> +{
> +	struct device_node *msi_node;
> +
> +	msi_node = of_parse_phandle(pp->dev->of_node,
> +				    "msi-parent", 0);
> +	if (!msi_node)
> +		return;
> +
> +	pp->msi = of_pci_find_msi_chip_by_node(msi_node);

How funny. The ITS is never registered there (actually, nobody seems to
register anything there anymore), so this will always return NULL. This
whole function is thus completely useless.

> +	of_node_put(msi_node);
> +
> +	if (pp->msi)
> +		pp->msi->dev = pp->dev;
> +}
> +
> +static void rockchip_pcie_enable_interrupts(struct rockchip_pcie_port *pp)
> +{
> +	pcie_write(pp, (CLIENT_INTERRUPTS << 16) &
> +		   (~CLIENT_INTERRUPTS), PCIE_CLIENT_INT_MASK);
> +	pcie_write(pp, CORE_INTERRUPTS, PCIE_CORE_INT_MASK);
> +}
> +
> +static int rockchip_pcie_intx_map(struct irq_domain *domain, unsigned int irq,
> +				  irq_hw_number_t hwirq)
> +{
> +	irq_set_chip_and_handler(irq, &dummy_irq_chip, handle_simple_irq);
> +	irq_set_chip_data(irq, domain->host_data);
> +
> +	return 0;
> +}
> +
> +static const struct irq_domain_ops intx_domain_ops = {
> +	.map = rockchip_pcie_intx_map,
> +};
> +
> +static int rockchip_pcie_init_irq_domain(struct rockchip_pcie_port *pp)
> +{
> +	struct device *dev = pp->dev;
> +	struct device_node *node = dev->of_node;
> +	struct device_node *pcie_intc_node =  of_get_next_child(node, NULL);

That's really ugly, as it depends on the layout of your DT.

> +
> +	if (!pcie_intc_node) {
> +		dev_err(dev, "No PCIe Intc node found\n");
> +		return PTR_ERR(pcie_intc_node);
> +	}
> +	pp->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
> +					       &intx_domain_ops, pp);

Why can't you just register your host controller as the interrupt
controller? You don't need an intermediate node for that.

> +	if (!pp->irq_domain) {
> +		dev_err(dev, "Failed to get a INTx IRQ domain\n");
> +		return PTR_ERR(pp->irq_domain);
> +	}
> +
> +	return 0;
> +}
> +
> +static irqreturn_t rockchip_pcie_subsys_irq_handler(int irq, void *arg)
> +{
> +	struct rockchip_pcie_port *pp = arg;
> +	u32 reg;
> +	u32 sub_reg;
> +
> +	reg = pcie_read(pp, PCIE_CLIENT_INT_STATUS);
> +	if (reg & LOC_INT) {
> +		dev_dbg(pp->dev, "local interrupt recived\n");
> +		sub_reg = pcie_read(pp, PCIE_CORE_INT_STATUS);
> +		if (sub_reg & PRFPE)
> +			dev_dbg(pp->dev, "Parity error detected while reading from the PNP Receive FIFO RAM\n");
> +
> +		if (sub_reg & CRFPE)
> +			dev_dbg(pp->dev, "Parity error detected while reading from the Completion Receive FIFO RAM\n");
> +
> +		if (sub_reg & RRPE)
> +			dev_dbg(pp->dev, "Parity error detected while reading from Replay Buffer RAM\n");
> +
> +		if (sub_reg & PRFO)
> +			dev_dbg(pp->dev, "Overflow occurred in the PNP Receive FIFO\n");
> +
> +		if (sub_reg & CRFO)
> +			dev_dbg(pp->dev, "Overflow occurred in the Completion Receive FIFO\n");
> +
> +		if (sub_reg & RT)
> +			dev_dbg(pp->dev, "Replay timer timed out\n");
> +
> +		if (sub_reg & RTR)
> +			dev_dbg(pp->dev, "Replay timer rolled over after 4 transmissions of the same TLP\n");
> +
> +		if (sub_reg & PE)
> +			dev_dbg(pp->dev, "Phy error detected on receive side\n");
> +
> +		if (sub_reg & MTR)
> +			dev_dbg(pp->dev, "Malformed TLP received from the link\n");
> +
> +		if (sub_reg & UCR)
> +			dev_dbg(pp->dev, "Malformed TLP received from the link\n");
> +
> +		if (sub_reg & FCE)
> +			dev_dbg(pp->dev, "An error was observed in the flow control advertisements from the other side\n");
> +
> +		if (sub_reg & CT)
> +			dev_dbg(pp->dev, "A request timed out waiting for completion\n");
> +
> +		if (sub_reg & UTC)
> +			dev_dbg(pp->dev, "Unmapped TC error\n");
> +
> +		if (sub_reg & MMVC)
> +			dev_dbg(pp->dev, "MSI mask register changes\n");
> +
> +		pcie_write(pp, sub_reg, PCIE_CORE_INT_STATUS);
> +	}
> +
> +	pcie_write(pp, reg, PCIE_CLIENT_INT_STATUS);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t rockchip_pcie_client_irq_handler(int irq, void *arg)
> +{
> +	struct rockchip_pcie_port *pp = arg;
> +	u32 reg;
> +
> +	reg = pcie_read(pp, PCIE_CLIENT_INT_STATUS);
> +	if (reg & LEGACY_DONE)
> +		dev_dbg(pp->dev, "legacy done interrupt recived\n");
> +
> +	if (reg & MSG_DONE)
> +		dev_dbg(pp->dev, "message done interrupt recived\n");
> +
> +	if (reg & HOT_RESET)
> +		dev_dbg(pp->dev, "hot reset interrupt recived\n");
> +
> +	if (reg & DPA_INT)
> +		dev_dbg(pp->dev, "dpa interrupt recived\n");
> +
> +	if (reg & FATAL_ERR)
> +		dev_dbg(pp->dev, "fatal error interrupt recived\n");
> +
> +	if (reg & DPA_INT)
> +		dev_dbg(pp->dev, "no fatal error interrupt recived\n");
> +
> +	if (reg & CORR_ERR)
> +		dev_dbg(pp->dev, "correctable error interrupt recived\n");
> +
> +	pcie_write(pp, reg, PCIE_CLIENT_INT_STATUS);
> +
> +	return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t rockchip_pcie_legacy_int_handler(int irq, void *arg)
> +{
> +	struct rockchip_pcie_port *pp = arg;
> +	u32 reg;
> +
> +	reg = pcie_read(pp, PCIE_CLIENT_INT_STATUS);
> +	reg = (reg & ROCKCHIP_PCIE_RPIFR1_INTR_MASK) >>
> +	       ROCKCHIP_PCIE_RPIFR1_INTR_SHIFT;
> +	generic_handle_irq(irq_find_mapping(pp->irq_domain, ffs(reg)));

NAK. What you have here is a chained interrupt controller, please
implement it as such.

> +
> +	pcie_write(pp, reg, PCIE_CLIENT_INT_STATUS);
> +	return IRQ_HANDLED;
> +}
> +
> +static int rockchip_pcie_prog_ob_atu(struct rockchip_pcie_port *pp,
> +				     int region_no,
> +				     int type, u8 num_pass_bits,
> +				     u32 lower_addr, u32 upper_addr)
> +{
> +	u32 ob_addr_0 = 0;
> +	u32 ob_addr_1 = 0;
> +	u32 ob_desc_0 = 0;
> +	u32 ob_desc_1 = 0;
> +	void __iomem *aw_base;
> +
> +	if (!pp)
> +		return -EINVAL;
> +	if (region_no >= MAX_AXI_WRAPPER_REGION_NUM)
> +		return -EINVAL;
> +	if ((num_pass_bits + 1) < 8)
> +		return -EINVAL;
> +	if (num_pass_bits > 63)
> +		return -EINVAL;
> +	if (region_no == 0) {
> +		if (AXI_REGION_0_SIZE < (2ULL << num_pass_bits))
> +		return -EINVAL;
> +	}
> +	if (region_no != 0) {
> +		if (AXI_REGION_SIZE < (2ULL << num_pass_bits))
> +		return -EINVAL;
> +	}
> +	aw_base = pp->apb_base + PCIE_CORE_AXI_CONF_BASE;
> +	aw_base += (region_no << OB_REG_SIZE_SHIFT);
> +
> +	ob_addr_0 = (ob_addr_0 &
> +		     ~0x0000003fU) | (num_pass_bits &
> +		     0x0000003fU);
> +	ob_addr_0 = (ob_addr_0 &
> +		     ~0xffffff00U) | (lower_addr & 0xffffff00U);
> +	ob_addr_1 = upper_addr;
> +	ob_desc_0 = (1 << 23 | type);
> +
> +	writel(ob_addr_0, aw_base);
> +	writel(ob_addr_1, aw_base + 0x4);
> +	writel(ob_desc_0, aw_base + 0x8);
> +	writel(ob_desc_1, aw_base + 0xc);
> +
> +	return 0;
> +}
> +
> +static int rockchip_pcie_prog_ib_atu(struct rockchip_pcie_port *pp,
> +				     int region_no,
> +				     u8 num_pass_bits,
> +				     u32 lower_addr,
> +				     u32 upper_addr)
> +{
> +	u32 ib_addr_0 = 0;
> +	u32 ib_addr_1 = 0;
> +	void __iomem *aw_base;
> +
> +	if (!pp)
> +		return -EINVAL;
> +	if (region_no > MAX_AXI_IB_ROOTPORT_REGION_NUM)
> +		return -EINVAL;
> +	if ((num_pass_bits + 1) < MIN_AXI_ADDR_BITS_PASSED)
> +		return -EINVAL;
> +	if (num_pass_bits > 63)
> +		return -EINVAL;
> +	aw_base = pp->apb_base + PCIE_CORE_AXI_INBOUND_BASE;
> +	aw_base += (region_no << IB_ROOT_PORT_REG_SIZE_SHIFT);
> +	ib_addr_0 = (ib_addr_0 &
> +		     ~0x0000003fU) | (num_pass_bits &
> +		     0x0000003fU);
> +
> +	ib_addr_0 = (ib_addr_0 & ~0xffffff00U) |
> +		     ((lower_addr << 8) & 0xffffff00U);
> +	ib_addr_1 = upper_addr;
> +	writel(ib_addr_0, aw_base);
> +	writel(ib_addr_1, aw_base + 0x4);
> +
> +	return 0;
> +}
> +
> +static int rockchip_pcie_probe(struct platform_device *pdev)
> +{
> +	struct rockchip_pcie_port *port;
> +	struct device *dev = &pdev->dev;
> +	struct pci_bus *bus, *child;
> +	struct resource_entry *win;
> +	int reg_no;
> +	int err = 0;
> +	int irq;
> +	LIST_HEAD(res);
> +
> +	if (!dev->of_node)
> +		return -ENODEV;
> +
> +	port = devm_kzalloc(dev, sizeof(*port), GFP_KERNEL);
> +	if (!port)
> +		return -ENOMEM;
> +
> +	irq = platform_get_irq_byname(pdev, "pcie-sys");
> +	if (irq < 0) {
> +		dev_err(dev, "missing pcie_sys IRQ resource\n");
> +		return -EINVAL;
> +	}
> +	err = devm_request_irq(dev, irq, rockchip_pcie_subsys_irq_handler,
> +			       IRQF_SHARED, "pcie-sys", port);
> +	if (err) {
> +		dev_err(dev, "failed to request pcie subsystem irq\n");
> +		return err;
> +	}
> +
> +	port->irq = platform_get_irq_byname(pdev, "pcie-legacy");
> +	if (port->irq < 0) {
> +		dev_err(dev, "missing pcie_legacy IRQ resource\n");
> +		return -EINVAL;
> +	}
> +	err = devm_request_irq(dev, port->irq,
> +			       rockchip_pcie_legacy_int_handler,
> +			       IRQF_SHARED,
> +			       "pcie-legacy",
> +			       port);
> +	if (err) {
> +		dev_err(&pdev->dev, "failed to request pcie-legacy irq\n");
> +		return err;
> +	}
> +
> +	irq = platform_get_irq_byname(pdev, "pcie-client");
> +	if (irq < 0) {
> +		dev_err(dev, "missing pcie-client IRQ resource\n");
> +		return -EINVAL;
> +	}
> +	err = devm_request_irq(dev, irq, rockchip_pcie_client_irq_handler,
> +			       IRQF_SHARED, "pcie-client", port);
> +	if (err) {
> +		dev_err(dev, "failed to request pcie client irq\n");
> +		return err;
> +	}
> +
> +	port->dev = dev;
> +	err = rockchip_pcie_parse_dt(port);
> +	if (err) {
> +		dev_err(dev, "Parsing DT failed\n");
> +		return err;
> +	}
> +
> +	err = rockchip_pcie_init_port(port);
> +	if (err)
> +		return err;
> +
> +	platform_set_drvdata(pdev, port);
> +
> +	rockchip_pcie_enable_interrupts(port);
> +	if (!IS_ENABLED(CONFIG_PCI_MSI)) {
> +		err = rockchip_pcie_init_irq_domain(port);
> +		if (err < 0)
> +			return err;
> +	}
> +
> +	err = of_pci_get_host_bridge_resources(dev->of_node, 0, 0xff,
> +					       &res, &port->io_base);
> +	if (err)
> +		return err;
> +	/* Get the I/O and memory ranges from DT */
> +	resource_list_for_each_entry(win, &res) {
> +		switch (resource_type(win->res)) {
> +		case IORESOURCE_IO:
> +			port->io = win->res;
> +			port->io->name = "I/O";
> +			port->io_size = resource_size(port->io);
> +			port->io_bus_addr = port->io->start - win->offset;
> +			err = pci_remap_iospace(port->io, port->io_base);
> +			if (err) {
> +				dev_warn(port->dev, "error %d: failed to map resource %pR\n",
> +					 err, port->io);
> +				continue;
> +			}
> +			break;
> +		case IORESOURCE_MEM:
> +			port->mem = win->res;
> +			port->mem->name = "MEM";
> +			port->mem_size = resource_size(port->mem);
> +			port->mem_bus_addr = port->mem->start - win->offset;
> +			break;
> +		case 0:
> +			port->cfg = win->res;
> +			break;
> +		case IORESOURCE_BUS:
> +			port->busn = win->res;
> +			break;
> +		default:
> +			continue;
> +		}
> +	}
> +
> +	pcie_write(port, 0x6040000, PCIE_RC_CONFIG_BASE + 0x8);
> +	pcie_write(port, 0x0, PCIE_CORE_CTRL_MGMT_BASE + 0x300);
> +
> +	pcie_write(port, (RC_REGION_0_ADDR_TRANS_L + RC_REGION_0_PASS_BITS),
> +		   PCIE_CORE_AXI_CONF_BASE);
> +	pcie_write(port, RC_REGION_0_ADDR_TRANS_H,
> +		   PCIE_CORE_AXI_CONF_BASE + 0x4);
> +	pcie_write(port, 0x0080000a, PCIE_CORE_AXI_CONF_BASE + 0x8);
> +	pcie_write(port, 0x00000000, PCIE_CORE_AXI_CONF_BASE + 0xc);
> +
> +	for (reg_no = 0; reg_no < (port->mem_size >> 20); reg_no++) {
> +		err = rockchip_pcie_prog_ob_atu(port, reg_no + 1,
> +						AXI_WRAPPER_MEM_WRITE,
> +						20 - 1,
> +						port->mem_bus_addr +
> +							(reg_no << 20),
> +						0);
> +		if (err) {
> +			dev_err(dev, "Program RC outbound atu failed\n");
> +			return err;
> +		}
> +	}
> +
> +	err = rockchip_pcie_prog_ib_atu(port, 2, 32 - 1, 0x0, 0);
> +	if (err) {
> +		dev_err(dev, "Program RC inbound atu failed\n");
> +		return err;
> +	}
> +
> +	rockchip_pcie_msi_enable(port);
> +
> +	port->root_bus_nr = port->busn->start;
> +	if (IS_ENABLED(CONFIG_PCI_MSI)) {
> +		bus = pci_scan_root_bus_msi(port->dev, port->root_bus_nr,
> +					    &rockchip_pcie_ops, port, &res,
> +					    port->msi);

You don't need this. The infrastructure will do the right thing for you.

> +	} else {
> +		bus = pci_scan_root_bus(&pdev->dev, 0,
> +					&rockchip_pcie_ops, port, &res);
> +	}
> +	if (!bus)
> +		return -ENOMEM;
> +
> +	if (!pci_has_flag(PCI_PROBE_ONLY)) {

Why do you have catter for the PCI_PROBE_ONLY case? Nobody should ever
use that for properly implemented HW.

> +		pci_bus_size_bridges(bus);
> +		pci_bus_assign_resources(bus);
> +		list_for_each_entry(child, &bus->children, node)
> +			pcie_bus_configure_settings(child);
> +	}
> +
> +	pci_bus_add_devices(bus);
> +
> +	return err;
> +}
> +
> +static int rockchip_pcie_remove(struct platform_device *pdev)
> +{
> +	struct rockchip_pcie_port *port = platform_get_drvdata(pdev);
> +
> +	clk_disable_unprepare(port->hclk_pcie);
> +	clk_disable_unprepare(port->aclk_perf_pcie);
> +	clk_disable_unprepare(port->aclk_pcie);
> +	clk_disable_unprepare(port->clk_pciephy_ref);
> +
> +	return 0;
> +}
> +
> +static const struct of_device_id rockchip_pcie_of_match[] = {
> +	{ .compatible = "rockchip,rk3399-pcie", },
> +	{}
> +};
> +
> +static struct platform_driver rockchip_pcie_driver = {
> +	.driver = {
> +		.name = "rockchip-pcie",
> +		.of_match_table = rockchip_pcie_of_match,
> +		.suppress_bind_attrs = true,
> +	},
> +	.probe = rockchip_pcie_probe,
> +	.remove = rockchip_pcie_remove,
> +};
> +module_platform_driver(rockchip_pcie_driver);
> +
> +MODULE_AUTHOR("Rockchip Inc");
> +MODULE_DESCRIPTION("Rockchip AXI PCIe driver");
> +MODULE_LICENSE("GPL v2");
> 

This definitely requires some rework for both the interrupt and MSI
parts. I'll leave Lorenzo to comment on the PCI side of things.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...


From balbi at kernel.org  Fri May 27 05:54:14 2016
From: balbi at kernel.org (Felipe Balbi)
Date: Fri, 27 May 2016 15:54:14 +0300
Subject: [PATCH v3 2/5] usb: dwc3: add dis_u2_freeclk_exists_quirk
In-Reply-To: <1464348488-20760-3-git-send-email-william.wu@rock-chips.com>
References: <1464348488-20760-1-git-send-email-william.wu@rock-chips.com>
 <1464348488-20760-3-git-send-email-william.wu@rock-chips.com>
Message-ID: <87eg8npsp5.fsf@linux.intel.com>


Hi,

William Wu <william.wu at rock-chips.com> writes:
> Add a quirk to clear the GUSB2PHYCFG.U2_FREECLK_EXISTS bit,
> which specifies whether the USB2.0 PHY provides a free-running
> PHY clock, which is active when the clock control input is active.
>
> Signed-off-by: William Wu <william.wu at rock-chips.com>

can you rebase on top of my testing/next? We're dropping pdata support.

-- 
balbi
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 818 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160527/83a77b26/attachment.sig>

From broonie at kernel.org  Fri May 27 13:23:12 2016
From: broonie at kernel.org (Mark Brown)
Date: Fri, 27 May 2016 21:23:12 +0100
Subject: [RESEND PATCH 5/6] ASoC: cdn-dp: Add cdn DP codec driver
In-Reply-To: <1464345942-4795-6-git-send-email-zyw@rock-chips.com>
References: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
 <1464345942-4795-6-git-send-email-zyw@rock-chips.com>
Message-ID: <20160527202312.GB29837@sirena.org.uk>

On Fri, May 27, 2016 at 06:45:41PM +0800, Chris Zhong wrote:
> codec driver get some interfaces from cdn-dp driver, than using those
> to set DP audio formats, corresponding to alsa formats.

I'm not seeing anything Rockchip specific in here...  DisplayPort is
backwards compatible with HDMI, shouldn't this be using the existing
hdmi-codec code?
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160527/8b915da1/attachment.sig>

From wsy2220 at gmail.com  Fri May 27 23:43:48 2016
From: wsy2220 at gmail.com (Shuyu Wei)
Date: Sat, 28 May 2016 14:43:48 +0800
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <5744EA24.7060806@gmx.de>
References: <20160518225529.GA18671@electric-eye.fr.zoreil.com>
 <573E2D0C.604@gmx.de>
 <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm> <5740E82F.8040903@gmx.de>
 <20160522091742.GA8681@debian-dorm> <57419853.9050701@gmx.de>
 <20160522223659.GB5086@electric-eye.fr.zoreil.com>
 <5743A9DD.8010202@gmx.de> <5744EA24.7060806@gmx.de>
Message-ID: <20160528064348.GA19649@debian-dorm>

On Wed, May 25, 2016 at 01:56:20AM +0200, Lino Sanfilippo wrote:
> Francois, Shuyu,
> 
> this is the patch with the discussed changes.
> 
> Shuyu it would be great if you could test this one. If it passes
> and there are no further objections I will resend it as a regular patch
> (including commit message, etc.) to the mailing list.
> 
> 
> diff --git a/drivers/net/ethernet/arc/emac_main.c b/drivers/net/ethernet/arc/emac_main.c
> index a3a9392..ec656b3 100644
> --- a/drivers/net/ethernet/arc/emac_main.c
> +++ b/drivers/net/ethernet/arc/emac_main.c
> @@ -153,18 +153,29 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>  {
>  	struct arc_emac_priv *priv = netdev_priv(ndev);
>  	struct net_device_stats *stats = &ndev->stats;
> +	unsigned int curr = priv->txbd_curr;
>  	unsigned int i;
>  
> +	/* Make sure buffers and txbd_curr are consistent */
> +	smp_rmb();
> +
>  	for (i = 0; i < TX_BD_NUM; i++) {
>  		unsigned int *txbd_dirty = &priv->txbd_dirty;
>  		struct arc_emac_bd *txbd = &priv->txbd[*txbd_dirty];
>  		struct buffer_state *tx_buff = &priv->tx_buff[*txbd_dirty];
> -		struct sk_buff *skb = tx_buff->skb;
> -		unsigned int info = le32_to_cpu(txbd->info);
> +		unsigned int info;
> +		struct sk_buff *skb;
>  
> -		if ((info & FOR_EMAC) || !txbd->data || !skb)
> +		if (*txbd_dirty == curr)
>  			break;
>  
> +		info = le32_to_cpu(txbd->info);
> +
> +		if (info & FOR_EMAC)
> +			break;
> +
> +		skb = tx_buff->skb;
> +
>  		if (unlikely(info & (DROP | DEFR | LTCL | UFLO))) {
>  			stats->tx_errors++;
>  			stats->tx_dropped++;
> @@ -195,8 +206,8 @@ static void arc_emac_tx_clean(struct net_device *ndev)
>  		*txbd_dirty = (*txbd_dirty + 1) % TX_BD_NUM;
>  	}
>  
> -	/* Ensure that txbd_dirty is visible to tx() before checking
> -	 * for queue stopped.
> +	/* Ensure that txbd_dirty is visible to tx() and we see the most recent
> +	 * value for txbd_curr.
>  	 */
>  	smp_mb();
>  
> @@ -680,27 +691,24 @@ static int arc_emac_tx(struct sk_buff *skb, struct net_device *ndev)
>  	dma_unmap_len_set(&priv->tx_buff[*txbd_curr], len, len);
>  
>  	priv->txbd[*txbd_curr].data = cpu_to_le32(addr);
> -
> -	/* Make sure pointer to data buffer is set */
> -	wmb();
> +	priv->tx_buff[*txbd_curr].skb = skb;
>  
>  	skb_tx_timestamp(skb);
>  
>  	*info = cpu_to_le32(FOR_EMAC | FIRST_OR_LAST_MASK | len);
>  
> -	/* Make sure info word is set */
> +	/* 1. Make sure that with respect to tx_clean everything is set up
> +	 * properly before we advance txbd_curr.
> +	 * 2. Make sure writes to DMA descriptors are completed before we inform
> +	 * the hardware.
> +	 */
>  	wmb();
>  
> -	priv->tx_buff[*txbd_curr].skb = skb;
> -
>  	/* Increment index to point to the next BD */
>  	*txbd_curr = (*txbd_curr + 1) % TX_BD_NUM;
>  
> -	/* Ensure that tx_clean() sees the new txbd_curr before
> -	 * checking the queue status. This prevents an unneeded wake
> -	 * of the queue in tx_clean().
> -	 */
> -	smp_mb();
> +	/* Ensure tx_clean() sees the updated value of txbd_curr */
> +	smp_wmb();
>  
>  	if (!arc_emac_tx_avail(priv)) {
>  		netif_stop_queue(ndev);

After some stress testing, it worked well most of the time.
But there is a chance that it may get stuck when I use 2 nc process
to send TCP packects at full speed.  Only when a new rx packet 
arrive can trigger it to run again. This happens only once per several
hours. No problem in UDP mode.  I'm not sure if it's related to tx code in
the driver.


From geert at linux-m68k.org  Sun May 29 02:21:38 2016
From: geert at linux-m68k.org (Geert Uytterhoeven)
Date: Sun, 29 May 2016 11:21:38 +0200
Subject: [PATCH 05/54] MAINTAINERS: Add file patterns for rockchip device
 tree bindings
In-Reply-To: <1575416.jfSztnP7S8@phil>
References: <1463907991-7916-1-git-send-email-geert@linux-m68k.org>
 <1463907991-7916-6-git-send-email-geert@linux-m68k.org>
 <1575416.jfSztnP7S8@phil>
Message-ID: <CAMuHMdVYd01kWvN5Gv_2RtPXFX2VP0nOx7Ys6=em35rk0HoOmA@mail.gmail.com>

Hi Heiko,

On Sun, May 22, 2016 at 11:27 AM, Heiko Stuebner <heiko at sntech.de> wrote:
> Am Sonntag, 22. Mai 2016, 11:05:42 schrieb Geert Uytterhoeven:
>> Submitters of device tree binding documentation may forget to CC
>> the subsystem maintainer if this is missing.
>
> The "N: rockchip" line at the bottom of the block catches this nicely
> already (also just verified with a get_maintainer.pl -f call), so I don't
> think this new more explicit line is really necessary?

Oh right, thanks! I (my bashery) only looked at direct references to
Documentation/devicetree/bindings. I complely missed the rare users of "N:".

Will drop this patch.

Gr{oetje,eeting}s,

                        Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds


From jh80.chung at samsung.com  Sun May 29 16:18:20 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Mon, 30 May 2016 08:18:20 +0900
Subject: [PATCH v2 1/2] mmc: dw_mmc: remove redundant of set_bit and
 clear_bit
In-Reply-To: <1464331000-16230-1-git-send-email-shawn.lin@rock-chips.com>
References: <CGME20160527063715epcas1p1584a3a6340d55ca1d912dc93f2d89bab@epcas1p1.samsung.com>
 <1464331000-16230-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <574B78BC.10700@samsung.com>

Hi Shawn,

Applied on my repository.
Thanks!

Best Regards,
Jaehoon Chung

On 05/27/2016 03:36 PM, Shawn Lin wrote:
> dw_mci_get_cd have already dealt with these for
> both of internal card-detect and gpio card-detect.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> 
> ---
> 
> Changes in v2: None
> 
>  drivers/mmc/host/dw_mmc.c | 5 +----
>  1 file changed, 1 insertion(+), 4 deletions(-)
> 
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 829a6ee..cb30e91 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -2616,10 +2616,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
>  		mmc->max_seg_size = mmc->max_req_size;
>  	}
>  
> -	if (dw_mci_get_cd(mmc))
> -		set_bit(DW_MMC_CARD_PRESENT, &slot->flags);
> -	else
> -		clear_bit(DW_MMC_CARD_PRESENT, &slot->flags);
> +	dw_mci_get_cd(mmc);
>  
>  	ret = mmc_add_host(mmc);
>  	if (ret)
> 



From jh80.chung at samsung.com  Sun May 29 16:18:48 2016
From: jh80.chung at samsung.com (Jaehoon Chung)
Date: Mon, 30 May 2016 08:18:48 +0900
Subject: [PATCH v2 2/2] mmc: dw_mmc: check card present before starting
 request
In-Reply-To: <1464331025-16275-1-git-send-email-shawn.lin@rock-chips.com>
References: <CGME20160527063809epcas1p37bab24c0ce09ace502a3dc8cea023887@epcas1p3.samsung.com>
 <1464331025-16275-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <574B78D8.50903@samsung.com>

Hi Shawn,

On 05/27/2016 03:37 PM, Shawn Lin wrote:
> The main reason to add this check is to avoid unnecessary
> mmc_request like the on-going cmd and the corresponding sbc
> if the card is removed. Although we have already checked this in
> dw_mci_handle_cd for runtime usage of sd card and dw_mci_init_slot
> for noremovable devices, but there is a timing gap before it really
> calls dw_mci_get_cd as mmc_detect_change needs some delay here.
> 
> Another gain here is that we could save some checkings of card status
> after sd card been removed.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>

Applied on my repository.
Thanks!

Best Regards,
Jaehoon Chung

> 
> ---
> 
> Changes in v2:
> - hold lock before dw_mci_queue_request
> 
>  drivers/mmc/host/dw_mmc.c | 7 ++++---
>  1 file changed, 4 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index cb30e91..2b4b3df 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -105,6 +105,7 @@ struct idmac_desc {
>  static bool dw_mci_reset(struct dw_mci *host);
>  static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
>  static int dw_mci_card_busy(struct mmc_host *mmc);
> +static int dw_mci_get_cd(struct mmc_host *mmc);
>  
>  #if defined(CONFIG_DEBUG_FS)
>  static int dw_mci_req_show(struct seq_file *s, void *v)
> @@ -1253,15 +1254,15 @@ static void dw_mci_request(struct mmc_host *mmc, struct mmc_request *mrq)
>  	 * atomic, otherwise the card could be removed in between and the
>  	 * request wouldn't fail until another card was inserted.
>  	 */
> -	spin_lock_bh(&host->lock);
>  
> -	if (!test_bit(DW_MMC_CARD_PRESENT, &slot->flags)) {
> -		spin_unlock_bh(&host->lock);
> +	if (!dw_mci_get_cd(mmc)) {
>  		mrq->cmd->error = -ENOMEDIUM;
>  		mmc_request_done(mmc, mrq);
>  		return;
>  	}
>  
> +	spin_lock_bh(&host->lock);
> +
>  	dw_mci_queue_request(host, slot, mrq);
>  
>  	spin_unlock_bh(&host->lock);
> 



From yamada.masahiro at socionext.com  Sun May 29 19:12:33 2016
From: yamada.masahiro at socionext.com (Masahiro Yamada)
Date: Mon, 30 May 2016 11:12:33 +0900
Subject: [PATCH] arm64: dts: drop "arm,
 amba-bus" in favor of "simple-bus" part 2
Message-ID: <1464574353-31477-1-git-send-email-yamada.masahiro@socionext.com>

Tree-wide replacement was done by commit 2ef7d5f342c1 (ARM, ARM64:
dts: drop "arm,amba-bus" in favor of "simple-bus"), but we have some
new users of "arm,amba-bus" at Linux 4.7-rc1.  Eliminate them now.

Signed-off-by: Masahiro Yamada <yamada.masahiro at socionext.com>
---

In order to not leave these compatible strings for the release,
is it OK to apply this patch for Linux 4.7 ?



 arch/arm64/boot/dts/lg/lg1312.dtsi       | 2 +-
 arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/arm64/boot/dts/lg/lg1312.dtsi b/arch/arm64/boot/dts/lg/lg1312.dtsi
index 3a4e9a2..fbafa24 100644
--- a/arch/arm64/boot/dts/lg/lg1312.dtsi
+++ b/arch/arm64/boot/dts/lg/lg1312.dtsi
@@ -125,7 +125,7 @@
 		#size-cells = <1>;
 		#interrupts-cells = <3>;
 
-		compatible = "arm,amba-bus";
+		compatible = "simple-bus";
 		interrupt-parent = <&gic>;
 		ranges;
 
diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
index 46f325a..d7f8e06 100644
--- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
@@ -163,7 +163,7 @@
 	};
 
 	amba {
-		compatible = "arm,amba-bus";
+		compatible = "simple-bus";
 		#address-cells = <2>;
 		#size-cells = <2>;
 		ranges;
-- 
1.9.1



From vinod.koul at intel.com  Sun May 29 20:33:21 2016
From: vinod.koul at intel.com (Vinod Koul)
Date: Mon, 30 May 2016 09:03:21 +0530
Subject: [RESEND PATCH 5/6] ASoC: cdn-dp: Add cdn DP codec driver
In-Reply-To: <20160527202312.GB29837@sirena.org.uk>
References: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
 <1464345942-4795-6-git-send-email-zyw@rock-chips.com>
 <20160527202312.GB29837@sirena.org.uk>
Message-ID: <20160530033321.GD16910@localhost>

On Fri, May 27, 2016 at 09:23:12PM +0100, Mark Brown wrote:
> On Fri, May 27, 2016 at 06:45:41PM +0800, Chris Zhong wrote:
> > codec driver get some interfaces from cdn-dp driver, than using those
> > to set DP audio formats, corresponding to alsa formats.
> 
> I'm not seeing anything Rockchip specific in here...  DisplayPort is
> backwards compatible with HDMI, shouldn't this be using the existing
> hdmi-codec code?


Yup, typically only difference between the two would be programming the
info frame for DP or HDMI, otherwise it is pretty much same stuff...

They should patch hdmi-codec for that, if that is not supported.

Thanks
-- 
~Vinod
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 819 bytes
Desc: Digital signature
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160530/b87a6f59/attachment.sig>

From zyw at rock-chips.com  Mon May 30 00:26:13 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Mon, 30 May 2016 15:26:13 +0800
Subject: [RESEND PATCH 5/6] ASoC: cdn-dp: Add cdn DP codec driver
In-Reply-To: <20160530033321.GD16910@localhost>
References: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
 <1464345942-4795-6-git-send-email-zyw@rock-chips.com>
 <20160527202312.GB29837@sirena.org.uk> <20160530033321.GD16910@localhost>
Message-ID: <574BEB15.20704@rock-chips.com>

Hi Mark & Vinod

Thanks for your suggestion, I am going to use this HDMI codec driver.
But it seems no one use it, currently.

On 05/30/2016 11:33 AM, Vinod Koul wrote:
> On Fri, May 27, 2016 at 09:23:12PM +0100, Mark Brown wrote:
>> On Fri, May 27, 2016 at 06:45:41PM +0800, Chris Zhong wrote:
>>> codec driver get some interfaces from cdn-dp driver, than using those
>>> to set DP audio formats, corresponding to alsa formats.
>> I'm not seeing anything Rockchip specific in here...  DisplayPort is
>> backwards compatible with HDMI, shouldn't this be using the existing
>> hdmi-codec code?
>
> Yup, typically only difference between the two would be programming the
> info frame for DP or HDMI, otherwise it is pretty much same stuff...
>
> They should patch hdmi-codec for that, if that is not supported.
>
> Thanks




From zhengxing at rock-chips.com  Mon May 30 00:32:45 2016
From: zhengxing at rock-chips.com (Xing Zheng)
Date: Mon, 30 May 2016 15:32:45 +0800
Subject: [PATCH v3] ASoC: rockchip: Add machine driver for
 MAX98357A/RT5514/DA7219
In-Reply-To: <1464267742-15312-1-git-send-email-zhengxing@rock-chips.com>
References: <1464267742-15312-1-git-send-email-zhengxing@rock-chips.com>
Message-ID: <574BEC9D.50007@rock-chips.com>

Hi,
Could any guys help me to review this patch?

Thanks.

On 2016?05?26? 21:02, Xing Zheng wrote:
> There are multi codec devices on the RK3399 platform, we can use
> this patch support and control these codecs.
>
> Signed-off-by: Xing Zheng<zhengxing at rock-chips.com>
> ---
>
> Changes in v3:
> - rename DOC to rockchip,rk3399-max98357a-rt5514-da7219.txt
> - rename compatible to rockchip,rk3399-max98357a-rt5514-da7219
> - rename source code to rk3399_max98357a_rt5514_da7219.c
>
> Changes in v2:
> - use the FS 256 to set mclks of the max98357a and rt5514 danamically
> - add more sample rate for da7219
>
>   .../rockchip,rk3399-max98357a-rt5514-da7219.txt    |   15 +
>   sound/soc/rockchip/Kconfig                         |   11 +
>   sound/soc/rockchip/Makefile                        |    2 +
>   .../soc/rockchip/rk3399_max98357a_rt5514_da7219.c  |  333 ++++++++++++++++++++
>   4 files changed, 361 insertions(+)
>   create mode 100644 Documentation/devicetree/bindings/sound/rockchip,rk3399-max98357a-rt5514-da7219.txt
>   create mode 100644 sound/soc/rockchip/rk3399_max98357a_rt5514_da7219.c
>
> diff --git a/Documentation/devicetree/bindings/sound/rockchip,rk3399-max98357a-rt5514-da7219.txt b/Documentation/devicetree/bindings/sound/rockchip,rk3399-max98357a-rt5514-da7219.txt
> new file mode 100644
> index 0000000..3ae603e
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/sound/rockchip,rk3399-max98357a-rt5514-da7219.txt
> @@ -0,0 +1,15 @@
> +ROCKCHIP with MAX98357A/RT5514/DA7219 codecs
> +
> +Required properties:
> +- compatible: "rockchip,rk3399-max98357a-rt5514-da7219"
> +- rockchip,cpu: The phandle of the Rockchip I2S controller that's
> +  connected to the codecs
> +- rockchip,codec: The phandle of the MAX98357A/RT5514/DA7219 codecs
> +
> +Example:
> +
> +sound {
> +	compatible = "rockchip,rk3399-max98357a-rt5514-da7219";
> +	rockchip,cpu =<&i2s0&i2s0&i2s1>;
> +	rockchip,codec =<&max98357a&headsetcodec&codec>;
> +};
> diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
> index f1e0c70..e5bd1f9 100644
> --- a/sound/soc/rockchip/Kconfig
> +++ b/sound/soc/rockchip/Kconfig
> @@ -41,3 +41,14 @@ config SND_SOC_ROCKCHIP_RT5645
>   	help
>   	  Say Y or M here if you want to add support for SoC audio on Rockchip
>   	  boards using the RT5645/RT5650 codec, such as Veyron.
> +
> +config SND_SOC_RK3399_MAX98357A_RT5514_DA7219
> +	tristate "ASoC support for Rockchip RK3399 boards using the MAX98357A/RT5514/DA7219"
> +	depends on SND_SOC_ROCKCHIP&&  GPIOLIB
> +	select SND_SOC_ROCKCHIP_I2S
> +	select SND_SOC_MAX98357A
> +	select SND_SOC_RT5514
> +	select SND_SOC_DA7219
> +	help
> +	  Say Y or M here if you want to add support for SoC audio on Rockchip RK3399
> +	  boards using the MAX98357A/RT5514/DA7219.
> diff --git a/sound/soc/rockchip/Makefile b/sound/soc/rockchip/Makefile
> index c0bf560..0d9ca0a 100644
> --- a/sound/soc/rockchip/Makefile
> +++ b/sound/soc/rockchip/Makefile
> @@ -7,6 +7,8 @@ obj-$(CONFIG_SND_SOC_ROCKCHIP_SPDIF) += snd-soc-rockchip-spdif.o
>
>   snd-soc-rockchip-max98090-objs := rockchip_max98090.o
>   snd-soc-rockchip-rt5645-objs := rockchip_rt5645.o
> +snd-soc-rk3399-max98357a-rt5514-da7219-objs := rk3399_max98357a_rt5514_da7219.o
>
>   obj-$(CONFIG_SND_SOC_ROCKCHIP_MAX98090) += snd-soc-rockchip-max98090.o
>   obj-$(CONFIG_SND_SOC_ROCKCHIP_RT5645) += snd-soc-rockchip-rt5645.o
> +obj-$(CONFIG_SND_SOC_RK3399_MAX98357A_RT5514_DA7219) += snd-soc-rk3399-max98357a-rt5514-da7219.o
> diff --git a/sound/soc/rockchip/rk3399_max98357a_rt5514_da7219.c b/sound/soc/rockchip/rk3399_max98357a_rt5514_da7219.c
> new file mode 100644
> index 0000000..ec88600
> --- /dev/null
> +++ b/sound/soc/rockchip/rk3399_max98357a_rt5514_da7219.c
> @@ -0,0 +1,333 @@
> +/*
> + * Rockchip machine ASoC driver for boards using MAX98357A/RT5514/DA7219
> + *
> + * Copyright (c) 2016, ROCKCHIP CORPORATION.  All rights reserved.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program.  If not, see<http://www.gnu.org/licenses/>.
> + */
> +
> +#include<linux/module.h>
> +#include<linux/platform_device.h>
> +#include<linux/slab.h>
> +#include<linux/gpio.h>
> +#include<linux/of_gpio.h>
> +#include<linux/delay.h>
> +#include<linux/spi/spi.h>
> +#include<sound/core.h>
> +#include<sound/jack.h>
> +#include<sound/pcm.h>
> +#include<sound/pcm_params.h>
> +#include<sound/soc.h>
> +#include "rockchip_i2s.h"
> +#include "../codecs/da7219.h"
> +#include "../codecs/da7219-aad.h"
> +#include "../codecs/rt5514.h"
> +
> +#define DRV_NAME "rk3399-max98357a-rt5514-da7219"
> +
> +#define SOUND_FS	256
> +
> +static struct snd_soc_jack rockchip_sound_jack;
> +
> +static const struct snd_soc_dapm_widget rockchip_dapm_widgets[] = {
> +	SND_SOC_DAPM_HP("Headphones", NULL),
> +	SND_SOC_DAPM_SPK("Speakers", NULL),
> +	SND_SOC_DAPM_MIC("Headset Mic", NULL),
> +	SND_SOC_DAPM_MIC("Int Mic", NULL),
> +};
> +
> +static const struct snd_soc_dapm_route rockchip_dapm_routes[] = {
> +	/* Input Lines */
> +	{"MIC", NULL, "Headset Mic"},
> +	{"DMIC1L", NULL, "Int Mic"},
> +	{"DMIC1R", NULL, "Int Mic"},
> +
> +	/* Output Lines */
> +	{"Headphones", NULL, "HPL"},
> +	{"Headphones", NULL, "HPR"},
> +	{"Speakers", NULL, "Speakers"},
> +};
> +
> +static const struct snd_kcontrol_new rockchip_controls[] = {
> +	SOC_DAPM_PIN_SWITCH("Headphones"),
> +	SOC_DAPM_PIN_SWITCH("Speakers"),
> +	SOC_DAPM_PIN_SWITCH("Headset Mic"),
> +	SOC_DAPM_PIN_SWITCH("Int Mic"),
> +};
> +
> +static int rockchip_sound_max98357a_hw_params(struct snd_pcm_substream *substream,
> +			     struct snd_pcm_hw_params *params)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_dapm_context *dapm =&rtd->card->dapm;
> +	unsigned int mclk;
> +	int ret;
> +
> +	/* max98357a supports these sample rates */
> +	switch (params_rate(params)) {
> +	case 8000:
> +	case 16000:
> +	case 48000:
> +	case 96000:
> +		mclk = params_rate(params) * SOUND_FS;
> +		break;
> +	default:
> +		dev_err(rtd->card->dev, "%s() doesn't support this sample rate: %d\n",
> +				__func__, params_rate(params));
> +		return -EINVAL;
> +	}
> +
> +	ret = snd_soc_dai_set_sysclk(rtd->cpu_dai, 0, mclk, 0);
> +	if (ret) {
> +		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
> +				__func__, mclk, ret);
> +		return ret;
> +	}
> +
> +	snd_soc_dapm_disable_pin(dapm, "Headphones");
> +	snd_soc_dapm_enable_pin(dapm, "Speakers");
> +	snd_soc_dapm_sync(dapm);
> +
> +	return 0;
> +}
> +
> +static int rockchip_sound_rt5514_hw_params(struct snd_pcm_substream *substream,
> +			     struct snd_pcm_hw_params *params)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
> +	struct snd_soc_dai *codec_dai = rtd->codec_dai;
> +	unsigned int mclk;
> +	int ret;
> +
> +	mclk = params_rate(params) * SOUND_FS;
> +
> +	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
> +				     SND_SOC_CLOCK_OUT);
> +	if (ret<  0) {
> +		dev_err(rtd->card->dev, "Can't set cpu clock out %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = snd_soc_dai_set_sysclk(codec_dai, RT5514_SCLK_S_MCLK,
> +				     mclk, SND_SOC_CLOCK_IN);
> +	if (ret) {
> +		dev_err(rtd->card->dev, "%s() error setting sysclk to %u: %d\n",
> +				__func__, params_rate(params) * 512, ret);
> +		return ret;
> +	}
> +
> +	return 0;
> +}
> +
> +static int rockchip_sound_da7219_hw_params(struct snd_pcm_substream *substream,
> +			     struct snd_pcm_hw_params *params)
> +{
> +	struct snd_soc_pcm_runtime *rtd = substream->private_data;
> +	struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
> +	struct snd_soc_dai *codec_dai = rtd->codec_dai;
> +	struct snd_soc_dapm_context *dapm =&rtd->card->dapm;
> +	int mclk, ret;
> +
> +	/* in bypass mode, the mclk has to be one of the frequencies below */
> +	switch (params_rate(params)) {
> +	case 8000:
> +	case 16000:
> +	case 24000:
> +	case 32000:
> +	case 48000:
> +	case 64000:
> +	case 96000:
> +		mclk = 12288000;
> +		break;
> +	case 11025:
> +	case 22050:
> +	case 44100:
> +	case 88200:
> +		mclk = 11289600;
> +		break;
> +	default:
> +		return -EINVAL;
> +	}
> +
> +	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk,
> +				     SND_SOC_CLOCK_OUT);
> +	if (ret<  0) {
> +		dev_err(codec_dai->dev, "Can't set cpu clock out %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk,
> +				     SND_SOC_CLOCK_IN);
> +	if (ret<  0) {
> +		dev_err(codec_dai->dev, "Can't set codec clock in %d\n", ret);
> +		return ret;
> +	}
> +
> +	ret = snd_soc_dai_set_pll(codec_dai, 0, DA7219_SYSCLK_MCLK, 0, 0);
> +	if (ret<  0) {
> +		dev_err(codec_dai->dev, "Can't set pll sysclk mclk %d\n", ret);
> +		return ret;
> +	}
> +
> +	snd_soc_dapm_disable_pin(dapm, "Speakers");
> +	snd_soc_dapm_enable_pin(dapm, "Headphones");
> +	snd_soc_dapm_sync(dapm);
> +
> +	return 0;
> +}
> +
> +static int rockchip_sound_da7219_init(struct snd_soc_pcm_runtime *rtd)
> +{
> +	struct snd_soc_codec *codec = rtd->codec_dais[0]->codec;
> +	int ret;
> +
> +	/* Enable Headset and 4 Buttons Jack detection */
> +	ret = snd_soc_card_jack_new(rtd->card, "Headset Jack",
> +				    SND_JACK_HEADSET |
> +				    SND_JACK_BTN_0 | SND_JACK_BTN_1 |
> +				    SND_JACK_BTN_2 | SND_JACK_BTN_3,
> +				&rockchip_sound_jack, NULL, 0);
> +
> +	if (ret) {
> +		dev_err(rtd->card->dev, "New Headset Jack failed! (%d)\n", ret);
> +		return ret;
> +	}
> +
> +	da7219_aad_jack_det(codec,&rockchip_sound_jack);
> +
> +	return 0;
> +}
> +
> +static struct snd_soc_ops rockchip_sound_max98357a_ops = {
> +	.hw_params = rockchip_sound_max98357a_hw_params,
> +};
> +
> +static struct snd_soc_ops rockchip_sound_rt5514_ops = {
> +	.hw_params = rockchip_sound_rt5514_hw_params,
> +};
> +
> +static struct snd_soc_ops rockchip_sound_da7219_ops = {
> +	.hw_params = rockchip_sound_da7219_hw_params,
> +};
> +
> +enum {
> +	DAILINK_MAX98357A,
> +	DAILINK_RT5514,
> +	DAILINK_DA7219,
> +};
> +
> +static struct snd_soc_dai_link rockchip_dailinks[] = {
> +	[DAILINK_MAX98357A] = {
> +		.name = "MAX98357A",
> +		.stream_name = "MAX98357A PCM",
> +		.codec_dai_name = "HiFi",
> +		.ops =&rockchip_sound_max98357a_ops,
> +		/* set max98357a as slave */
> +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
> +			SND_SOC_DAIFMT_CBS_CFS,
> +	},
> +	[DAILINK_RT5514] = {
> +		.name = "RT5514",
> +		.stream_name = "RT5514 PCM",
> +		.codec_dai_name = "rt5514-aif1",
> +		.ops =&rockchip_sound_rt5514_ops,
> +		/* set rt5514 as slave */
> +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
> +			SND_SOC_DAIFMT_CBS_CFS,
> +	},
> +	[DAILINK_DA7219] = {
> +		.name = "DA7219",
> +		.stream_name = "DA7219 PCM",
> +		.codec_dai_name = "da7219-hifi",
> +		.init = rockchip_sound_da7219_init,
> +		.ops =&rockchip_sound_da7219_ops,
> +		/* set da7219 as slave */
> +		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
> +			SND_SOC_DAIFMT_CBS_CFS,
> +	},
> +};
> +
> +static struct snd_soc_card rockchip_sound_card = {
> +	.name = "rk3399-max98357a-rt5514-da7219",
> +	.owner = THIS_MODULE,
> +	.dai_link = rockchip_dailinks,
> +	.num_links =  ARRAY_SIZE(rockchip_dailinks),
> +	.dapm_widgets = rockchip_dapm_widgets,
> +	.num_dapm_widgets = ARRAY_SIZE(rockchip_dapm_widgets),
> +	.dapm_routes = rockchip_dapm_routes,
> +	.num_dapm_routes = ARRAY_SIZE(rockchip_dapm_routes),
> +	.controls = rockchip_controls,
> +	.num_controls = ARRAY_SIZE(rockchip_controls),
> +};
> +
> +static int rockchip_sound_probe(struct platform_device *pdev)
> +{
> +	struct snd_soc_card *card =&rockchip_sound_card;
> +	struct device_node *cpu_node;
> +	int i, ret;
> +
> +	for (i = 0; i<  card->num_links; i++) {
> +		cpu_node = of_parse_phandle(pdev->dev.of_node,
> +					 "rockchip,cpu", i);
> +		if (!cpu_node) {
> +			dev_err(&pdev->dev, "Property[%d] 'rockchip,cpu' missing or invalid\n", i);
> +			return -EINVAL;
> +		}
> +
> +		rockchip_dailinks[i].platform_of_node = cpu_node;
> +		rockchip_dailinks[i].cpu_of_node = cpu_node;
> +
> +		rockchip_dailinks[i].codec_of_node =
> +			of_parse_phandle(pdev->dev.of_node, "rockchip,codec", i);
> +		if (!rockchip_dailinks[i].codec_of_node) {
> +			dev_err(&pdev->dev,
> +				"Property[%d] 'rockchip,codec' missing or invalid\n", i);
> +			return -EINVAL;
> +		}
> +	}
> +
> +	card->dev =&pdev->dev;
> +	platform_set_drvdata(pdev, card);
> +
> +	ret = devm_snd_soc_register_card(&pdev->dev, card);
> +	if (ret)
> +		dev_err(&pdev->dev, "%s snd_soc_register_card fail %d\n",
> +			__func__, ret);
> +
> +	return ret;
> +}
> +
> +static const struct of_device_id rockchip_sound_of_match[] = {
> +	{ .compatible = "rockchip,rk3399-max98357a-rt5514-da7219", },
> +	{},
> +};
> +
> +static struct platform_driver rockchip_sound_driver = {
> +	.probe = rockchip_sound_probe,
> +	.driver = {
> +		.name = DRV_NAME,
> +		.of_match_table = rockchip_sound_of_match,
> +#ifdef CONFIG_PM
> +		.pm =&snd_soc_pm_ops,
> +#endif
> +	},
> +};
> +
> +module_platform_driver(rockchip_sound_driver);
> +
> +MODULE_AUTHOR("Xing Zheng<zhengxing at rock-chips.com>");
> +MODULE_DESCRIPTION("Rockchip ASoC Machine Driver");
> +MODULE_LICENSE("GPL v2");
> +MODULE_ALIAS("platform:" DRV_NAME);
> +MODULE_DEVICE_TABLE(of, rockchip_sound_of_match);


-- 
- Xing Zheng





From jsarha at ti.com  Mon May 30 00:47:52 2016
From: jsarha at ti.com (Jyri Sarha)
Date: Mon, 30 May 2016 10:47:52 +0300
Subject: [RESEND PATCH 5/6] ASoC: cdn-dp: Add cdn DP codec driver
In-Reply-To: <574BEB15.20704@rock-chips.com>
References: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
 <1464345942-4795-6-git-send-email-zyw@rock-chips.com>
 <20160527202312.GB29837@sirena.org.uk> <20160530033321.GD16910@localhost>
 <574BEB15.20704@rock-chips.com>
Message-ID: <574BF028.70102@ti.com>

On 05/30/16 10:26, Chris Zhong wrote:
> Hi Mark & Vinod
> 
> Thanks for your suggestion, I am going to use this HDMI codec driver.
> But it seems no one use it, currently.
> 

There is three users working on getting their code accepted in main
line. I have been trying to get my tda998x patches reviewed for some
time now, but not lately, because I have been busy with my other tasks.

The two others are Philipp Zabel and Arnaud Pouliquen, both in cc. Not
sure if they actually have some patches already queued for mainline.

Best regards,
Jyri

> On 05/30/2016 11:33 AM, Vinod Koul wrote:
>> On Fri, May 27, 2016 at 09:23:12PM +0100, Mark Brown wrote:
>>> On Fri, May 27, 2016 at 06:45:41PM +0800, Chris Zhong wrote:
>>>> codec driver get some interfaces from cdn-dp driver, than using those
>>>> to set DP audio formats, corresponding to alsa formats.
>>> I'm not seeing anything Rockchip specific in here...  DisplayPort is
>>> backwards compatible with HDMI, shouldn't this be using the existing
>>> hdmi-codec code?
>>
>> Yup, typically only difference between the two would be programming the
>> info frame for DP or HDMI, otherwise it is pretty much same stuff...
>>
>> They should patch hdmi-codec for that, if that is not supported.
>>
>> Thanks
> 
> 



From heiko at sntech.de  Mon May 30 03:19:21 2016
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Mon, 30 May 2016 12:19:21 +0200
Subject: [PATCH] arm64: dts: drop "arm,
 amba-bus" in favor of "simple-bus" part 2
In-Reply-To: <1464574353-31477-1-git-send-email-yamada.masahiro@socionext.com>
References: <1464574353-31477-1-git-send-email-yamada.masahiro@socionext.com>
Message-ID: <3072536.5uGCiTBfGN@diego>

Am Montag, 30. Mai 2016, 11:12:33 schrieb Masahiro Yamada:
> Tree-wide replacement was done by commit 2ef7d5f342c1 (ARM, ARM64:
> dts: drop "arm,amba-bus" in favor of "simple-bus"), but we have some
> new users of "arm,amba-bus" at Linux 4.7-rc1.  Eliminate them now.
> 
> Signed-off-by: Masahiro Yamada <yamada.masahiro at socionext.com>

For the Rockchip part,
Acked-by: Heiko Stuebner <heiko at sntech.de>

> ---
> 
> In order to not leave these compatible strings for the release,
> is it OK to apply this patch for Linux 4.7 ?
> 
> 
> 
>  arch/arm64/boot/dts/lg/lg1312.dtsi       | 2 +-
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm64/boot/dts/lg/lg1312.dtsi
> b/arch/arm64/boot/dts/lg/lg1312.dtsi index 3a4e9a2..fbafa24 100644
> --- a/arch/arm64/boot/dts/lg/lg1312.dtsi
> +++ b/arch/arm64/boot/dts/lg/lg1312.dtsi
> @@ -125,7 +125,7 @@
>  		#size-cells = <1>;
>  		#interrupts-cells = <3>;
> 
> -		compatible = "arm,amba-bus";
> +		compatible = "simple-bus";
>  		interrupt-parent = <&gic>;
>  		ranges;
> 
> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> b/arch/arm64/boot/dts/rockchip/rk3399.dtsi index 46f325a..d7f8e06 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -163,7 +163,7 @@
>  	};
> 
>  	amba {
> -		compatible = "arm,amba-bus";
> +		compatible = "simple-bus";
>  		#address-cells = <2>;
>  		#size-cells = <2>;
>  		ranges;



From marc.zyngier at arm.com  Mon May 30 04:08:36 2016
From: marc.zyngier at arm.com (Marc Zyngier)
Date: Mon, 30 May 2016 12:08:36 +0100
Subject: [PATCH 1/2] Documentation: add binding description of Rockchip
 PCIe controller
In-Reply-To: <1463740146-7106-1-git-send-email-shawn.lin@rock-chips.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740146-7106-1-git-send-email-shawn.lin@rock-chips.com>
Message-ID: <20160530120836.290f0d16@arm.com>

On Fri, 20 May 2016 18:29:06 +0800
Shawn Lin <shawn.lin at rock-chips.com> wrote:

> This patch add some required and optional properties for Rockchip
> PCIe controller. Also we add a example for how to use it.
> 
> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
> 
> ---
> 
>  .../devicetree/bindings/pci/rockchip-pcie.txt      | 93 ++++++++++++++++++++++
>  1 file changed, 93 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/pci/rockchip-pcie.txt
> 
> diff --git a/Documentation/devicetree/bindings/pci/rockchip-pcie.txt b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
> new file mode 100644
> index 0000000..69a0804
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
> @@ -0,0 +1,93 @@
> +* Rockchip AXI PCIe Root Port Bridge DT description
> +
> +Required properties:
> +- #address-cells: Address representation for root ports, set to <3>
> +- #size-cells: Size representation for root ports, set to <2>
> +- #interrupt-cells: specifies the number of cells needed to encode an
> +		interrupt source. The value must be 1.
> +- compatible: Should contain "rockchip,rk3399-pcie"
> +- reg: Two register ranges as listed in the reg-names property
> +- reg-names: The first entry must be "axi-base" for the core registers
> +	The second entry must be "apb-base" for the client pcie registers
> +- clocks: Must contain an entry for each entry in clock-names.
> +		See ../clocks/clock-bindings.txt for details.
> +- clock-names: Must include the following entries:
> +	- "aclk_pcie"
> +	- "aclk_perf_pcie"
> +	- "hclk_pcie"
> +	- "clk_pciephy_ref"
> +- interrupts: Three interrupt entries must be specified.
> +- interrupt-names: Must include the following names
> +	- "pcie-sys"
> +	- "pcie-legacy"
> +	- "pcie-client"
> +- resets: Must contain five entries for each entry in reset-names.
> +	   See ../reset/reset.txt for details.
> +- reset-names: Must include the following names
> +	- "phy-rst"
> +	- "core-rst"
> +	- "mgmt-rst"
> +	- "mgmt-sticky-rst"
> +	- "pipe-rst"
> +- rockchip,grf: phandle to the syscon managing the "general register files"
> +- pcie-conf: offset of pcie client block for  configuration
> +- pcie-status: offset of pcie client block for status
> +- pcie-laneoff: offset of pcie client block for lane
> +- msi-parent: Link to the hardware entity that serves as the Message
> +- pinctrl-names : The pin control state names
> +- pinctrl-0: The "default" pinctrl state
> +- interrupt-map-mask and interrupt-map: standard PCI properties
> +- interrupt-controller: identifies the node as an interrupt controller
> +
> +Optional Property:
> +- ep-gpios: contain the entry for pre-reset gpio
> +- num-lanes: number of lanes to use
> +- assigned-clocks, assigned-clock-parents and assigned-clock-rates: standard
> +		   clock bindings. See ../clock/clock-bindings.txt
> +
> +Example:
> +
> +pci_express: axi-pcie at f8000000 {
> +	#address-cells = <3>;
> +	#size-cells = <2>;
> +	compatible = "rockchip,rk3399-pcie";
> +	clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>,
> +		 <&cru PCLK_PCIE>, <&cru SCLK_PCIEPHY_REF>;
> +	clock-names = "aclk_pcie", "aclk_perf_pcie",
> +		      "hclk_pcie", "clk_pciephy_ref";
> +	bus-range = <0x0 0x1>;
> +	interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>,
> +		     <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
> +	interrupt-names: "pcie-sys", "pcie-legacy", "pcie-client";
> +	assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
> +	assigned-clock-parents = <&cru SCLK_PCIEPHY_REF100M>;
> +	assigned-clock-rates = <100000000>;
> +	ep-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
> +	ranges = < 0x82000000 0 0xfa000000 0x0 0xfa000000 0 0x600000
> +		   0x81000000 0 0xfa600000 0x0 0xfa600000 0 0x100000 >;
> +	num-lanes = <4>;
> +	reg = < 0x0 0xf8000000 0x0 0x2000000 >, < 0x0 0xfd000000 0x0 0x1000000 >;
> +	reg-name = "axi-base", "apb-base";
> +	resets = <&cru SRST_PCIEPHY>, <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>,
> +		 <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>;
> +	reset-names = "phy-rst", "core-rst", "mgmt-rst", "mgmt-sticky-rst", "pipe-rst";
> +	rockchip,grf = <&grf>;
> +	pcie-conf = <0xe220>;
> +	pcie-status = <0xe2a4>;
> +	pcie-laneoff = <0xe214>;
> +	pinctrl-names = "default";
> +	pinctrl-0 = <&pcie_clkreq>;
> +	msi-parent = <&its>;

We've moved away from bare msi-parent for the ITS (notice that the
binding mandates #msi-cells = <1>). So what you need here is an msi-map
(as described in Documentation/devicetree/bindings/pci/pci-msi.txt).

Do you have an IOMMU (or some other remapping HW) between the RC and the
GIC ITS? If so, yo may have to describe the mappings between the PCIe
RID and the ITS DevID in this msi-map.

> +	#interrupt-cells = <1>;
> +	interrupt-map-mask = <0 0 0 7>;
> +	interrupt-map = <0 0 0 1 &pcie_0 1>,
> +			<0 0 0 2 &pcie_0 2>,
> +			<0 0 0 3 &pcie_0 3>,
> +			<0 0 0 4 &pcie_0 4>;
> +	pcie_0: interrupt-controller {
> +		interrupt-controller;
> +		#address-cells = <0>;
> +		#interrupt-cells = <1>;
> +	};
> +
> +};

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny.


From arnaud.pouliquen at st.com  Mon May 30 05:26:01 2016
From: arnaud.pouliquen at st.com (Arnaud Pouliquen)
Date: Mon, 30 May 2016 14:26:01 +0200
Subject: [RESEND PATCH 5/6] ASoC: cdn-dp: Add cdn DP codec driver
In-Reply-To: <574BF028.70102@ti.com>
References: <1464345942-4795-1-git-send-email-zyw@rock-chips.com>
 <1464345942-4795-6-git-send-email-zyw@rock-chips.com>
 <20160527202312.GB29837@sirena.org.uk> <20160530033321.GD16910@localhost>
 <574BEB15.20704@rock-chips.com> <574BF028.70102@ti.com>
Message-ID: <574C3159.3010507@st.com>



On 05/30/2016 09:47 AM, Jyri Sarha wrote:
> On 05/30/16 10:26, Chris Zhong wrote:
>> Hi Mark & Vinod
>>
>> Thanks for your suggestion, I am going to use this HDMI codec driver.
>> But it seems no one use it, currently.
>>
> 
> There is three users working on getting their code accepted in main
> line. I have been trying to get my tda998x patches reviewed for some
> time now, but not lately, because I have been busy with my other tasks.
> 
> The two others are Philipp Zabel and Arnaud Pouliquen, both in cc. Not
> sure if they actually have some patches already queued for mainline.
Hi,
hdmi_codec is now available in DRM_next branch, this should allow us to
push DRM patches in mainline...

Best Regards
Arnaud
> 
> Best regards,
> Jyri
> 
>> On 05/30/2016 11:33 AM, Vinod Koul wrote:
>>> On Fri, May 27, 2016 at 09:23:12PM +0100, Mark Brown wrote:
>>>> On Fri, May 27, 2016 at 06:45:41PM +0800, Chris Zhong wrote:
>>>>> codec driver get some interfaces from cdn-dp driver, than using those
>>>>> to set DP audio formats, corresponding to alsa formats.
>>>> I'm not seeing anything Rockchip specific in here...  DisplayPort is
>>>> backwards compatible with HDMI, shouldn't this be using the existing
>>>> hdmi-codec code?
>>>
>>> Yup, typically only difference between the two would be programming the
>>> info frame for DP or HDMI, otherwise it is pretty much same stuff...
>>>
>>> They should patch hdmi-codec for that, if that is not supported.
>>>
>>> Thanks
>>
>>
> 


From broonie at kernel.org  Mon May 30 09:03:57 2016
From: broonie at kernel.org (Mark Brown)
Date: Mon, 30 May 2016 17:03:57 +0100
Subject: [PATCH v3] ASoC: rockchip: Add machine driver for
 MAX98357A/RT5514/DA7219
In-Reply-To: <574BEC9D.50007@rock-chips.com>
References: <1464267742-15312-1-git-send-email-zhengxing@rock-chips.com>
 <574BEC9D.50007@rock-chips.com>
Message-ID: <20160530160357.GQ29837@sirena.org.uk>

On Mon, May 30, 2016 at 03:32:45PM +0800, Xing Zheng wrote:
> Hi,
> Could any guys help me to review this patch?

Please don't send content free pings and please allow a reasonable time
for review.  People get busy, go on holiday, attend conferences and so 
on so unless there is some reason for urgency (like critical bug fixes)
please allow at least a couple of weeks for review.  If there have been
review comments then people may be waiting for those to be addressed.
Sending content free pings just adds to the mail volume (if they are
seen at all) and if something has gone wrong you'll have to resend the
patches anyway.

Please don't top post, reply in line with needed context.  This allows
readers to readily follow the flow of conversation and understand what
you are talking about and also helps ensure that everything in the
discussion is being addressed.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 473 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-rockchip/attachments/20160530/5e060bd5/attachment.sig>

From LinoSanfilippo at gmx.de  Mon May 30 14:41:22 2016
From: LinoSanfilippo at gmx.de (Lino Sanfilippo)
Date: Mon, 30 May 2016 23:41:22 +0200
Subject: [PATCH v2] ethernet:arc: Fix racing of TX ring buffer
In-Reply-To: <20160528064348.GA19649@debian-dorm>
References: <20160518225529.GA18671@electric-eye.fr.zoreil.com>
 <573E2D0C.604@gmx.de> <20160520003145.GA22420@electric-eye.fr.zoreil.com>
 <20160521160910.GA14945@debian-dorm> <5740E82F.8040903@gmx.de>
 <20160522091742.GA8681@debian-dorm> <57419853.9050701@gmx.de>
 <20160522223659.GB5086@electric-eye.fr.zoreil.com> <5743A9DD.8010202@gmx.de>
 <5744EA24.7060806@gmx.de> <20160528064348.GA19649@debian-dorm>
Message-ID: <574CB382.7030102@gmx.de>

Hi Shuyu,

On 28.05.2016 08:43, Shuyu Wei wrote:
> 
> After some stress testing, it worked well most of the time.
> But there is a chance that it may get stuck when I use 2 nc process
> to send TCP packects at full speed.  Only when a new rx packet 
> arrive can trigger it to run again. This happens only once per several
> hours. No problem in UDP mode.  I'm not sure if it's related to tx code in
> the driver.
> 

This sounds strange. One reason I could imagine for such an issue is that 
occassionally tx completion interrupts get lost: 
In this case skbs may not be freed (or be freed too late) which may result in a TCP
stream getting stuck, because each skb belongs to a socket and there is a limit for
the allowed number of skbs per socket. TCP would only proceed if the number of pending 
skbs falls under this limit again but since the tx completion irq is lost, the only thing 
that could trigger the tx completion handler is another irq, e.g for a received packet.
At least this could explain what you observed.

Did you see the same issues with the patch before (the one that, as you wrote,
survived a whole night of stress testing)?

Lino


From daniel.lezcano at linaro.org  Mon May 30 16:09:45 2016
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Tue, 31 May 2016 01:09:45 +0200
Subject: [PATCH 2/5] clocksource: rockchip: remove unnecessary clear irq
 before request_irq
In-Reply-To: <1464169802-6033-3-git-send-email-wxt@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-3-git-send-email-wxt@rock-chips.com>
Message-ID: <574CC839.60608@linaro.org>

On 05/25/2016 11:49 AM, Caesar Wang wrote:
> From: Huang Tao <huangtao at rock-chips.com>
>
> rk_timer_interrupt_clear and rk_timer_disable is unnecessary before
> request_irq. Timer should keep disabled before booting Linux.

That's true in the perfect world :/ Some version has u-boot letting the 
timer with irq enabled, therefore as soon as request_irq is done, an irq 
fires and leads to a kernel panic.

On the other side, this timer is not used on the other rockchip version 
than rk3399 because of no need of a broadcast timer, so removing these 
two lines may be acceptable.

Can try the changes with another board, eg rk3288 (and forcing to use 
this timer). Can you do the test and confirm it does not break with 
different version of u-boot ?

Thanks!

   -- Daniel

> Signed-off-by: Huang Tao <huangtao at rock-chips.com>
> Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Tested-by: Jianqun Xu <jay.xu at rock-chips.com>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> ---
>
>   drivers/clocksource/rockchip_timer.c | 3 ---
>   1 file changed, 3 deletions(-)
>
> diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
> index b991b28..b93fed6 100644
> --- a/drivers/clocksource/rockchip_timer.c
> +++ b/drivers/clocksource/rockchip_timer.c
> @@ -158,9 +158,6 @@ static void __init rk_timer_init(struct device_node *np)
>   	ce->cpumask = cpumask_of(0);
>   	ce->rating = 250;
>
> -	rk_timer_interrupt_clear(ce);
> -	rk_timer_disable(ce);
> -
>   	ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
>   	if (ret) {
>   		pr_err("Failed to initialize '%s': %d\n", TIMER_NAME, ret);
>


-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog



From daniel.lezcano at linaro.org  Mon May 30 16:16:46 2016
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Tue, 31 May 2016 01:16:46 +0200
Subject: [PATCH 3/5] clocksource: rockchip: add dynamic irq flag to the
 timer
In-Reply-To: <1464169802-6033-4-git-send-email-wxt@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-4-git-send-email-wxt@rock-chips.com>
Message-ID: <574CC9DE.1050501@linaro.org>

On 05/25/2016 11:50 AM, Caesar Wang wrote:
> From: Huang Tao <huangtao at rock-chips.com>
>
> The rockchip timer is broadcast timer. Add CLOCK_EVT_FEAT_DYNIRQ
> flag and set cpumask to all cpu to save power by avoid unnecessary
> wakeups and IPIs.
>
> Signed-off-by: Huang Tao <huangtao at rock-chips.com>
> Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Tested-by: Jianqun Xu <jay.xu at rock-chips.com>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> ---
>
>   drivers/clocksource/rockchip_timer.c | 5 +++--
>   1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
> index b93fed6..f3dfb1a 100644
> --- a/drivers/clocksource/rockchip_timer.c
> +++ b/drivers/clocksource/rockchip_timer.c
> @@ -150,12 +150,13 @@ static void __init rk_timer_init(struct device_node *np)
>   	}
>
>   	ce->name = TIMER_NAME;
> -	ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
> +	ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
> +		       CLOCK_EVT_FEAT_DYNIRQ;
>   	ce->set_next_event = rk_timer_set_next_event;
>   	ce->set_state_shutdown = rk_timer_shutdown;
>   	ce->set_state_periodic = rk_timer_set_periodic;
>   	ce->irq = irq;
> -	ce->cpumask = cpumask_of(0);
> +	ce->cpumask = cpu_all_mask;

s/cpu_all_mask/cpu_possible_mask/

>   	ce->rating = 250;
>
>   	ret = request_irq(irq, rk_timer_interrupt, IRQF_TIMER, TIMER_NAME, ce);
>


-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog



From chanho.min at lge.com  Mon May 30 16:25:27 2016
From: chanho.min at lge.com (Chanho Min)
Date: Tue, 31 May 2016 08:25:27 +0900
Subject: [PATCH] arm64: dts: drop "arm,
 amba-bus" in favor of "simple-bus" part 2
In-Reply-To: <1464574353-31477-1-git-send-email-yamada.masahiro@socionext.com>
References: <1464574353-31477-1-git-send-email-yamada.masahiro@socionext.com>
Message-ID: <021901d1baca$8ddf8050$a99e80f0$@lge.com>

> Subject: [PATCH] arm64: dts: drop "arm,amba-bus" in favor of "simple-bus" part
> 2
> 
> Tree-wide replacement was done by commit 2ef7d5f342c1 (ARM, ARM64:
> dts: drop "arm,amba-bus" in favor of "simple-bus"), but we have some
> new users of "arm,amba-bus" at Linux 4.7-rc1.  Eliminate them now.
> 
> Signed-off-by: Masahiro Yamada <yamada.masahiro at socionext.com>
> ---
> 
> In order to not leave these compatible strings for the release,
> is it OK to apply this patch for Linux 4.7 ?
> 
> 
> 
>  arch/arm64/boot/dts/lg/lg1312.dtsi       | 2 +-
>  arch/arm64/boot/dts/rockchip/rk3399.dtsi | 2 +-
>  2 files changed, 2 insertions(+), 2 deletions(-)
> 

> diff --git a/arch/arm64/boot/dts/lg/lg1312.dtsi
> b/arch/arm64/boot/dts/lg/lg1312.dtsi
> index 3a4e9a2..fbafa24 100644
> --- a/arch/arm64/boot/dts/lg/lg1312.dtsi
> +++ b/arch/arm64/boot/dts/lg/lg1312.dtsi
> @@ -125,7 +125,7 @@
>  		#size-cells = <1>;
>  		#interrupts-cells = <3>;
> 
> -		compatible = "arm,amba-bus";
> +		compatible = "simple-bus";
>  		interrupt-parent = <&gic>;
>  		ranges;
> 

Acked-by: Chanho Min <chanho.min at lge.com>

> diff --git a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> index 46f325a..d7f8e06 100644
> --- a/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> +++ b/arch/arm64/boot/dts/rockchip/rk3399.dtsi
> @@ -163,7 +163,7 @@
>  	};
> 
>  	amba {
> -		compatible = "arm,amba-bus";
> +		compatible = "simple-bus";
>  		#address-cells = <2>;
>  		#size-cells = <2>;
>  		ranges;
> --
> 1.9.1



From daniel.lezcano at linaro.org  Mon May 30 16:28:52 2016
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Tue, 31 May 2016 01:28:52 +0200
Subject: [PATCH 4/5] clocksource: rockchip: add support for rk3399 SoC
In-Reply-To: <1464169802-6033-5-git-send-email-wxt@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-5-git-send-email-wxt@rock-chips.com>
Message-ID: <574CCCB4.1030001@linaro.org>

On 05/25/2016 11:50 AM, Caesar Wang wrote:
> From: Huang Tao <huangtao at rock-chips.com>
>
> The CONTROL register offset is different from old SoCs.
> For Linux driver, there are not functional changes at all.
> Let's call it v2.
>
> Signed-off-by: Huang Tao <huangtao at rock-chips.com>
> Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
> Cc: Thomas Gleixner <tglx at linutronix.de>
> Cc: Heiko Stuebner <heiko at sntech.de>
> Tested-by: Jianqun Xu <jay.xu at rock-chips.com>
> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
> ---

That's hackish.

Please consider something like:

diff --git a/drivers/clocksource/rockchip_timer.c 
b/drivers/clocksource/rockchip_timer.c
index b991b28..b6ba6f9 100644
--- a/drivers/clocksource/rockchip_timer.c
+++ b/drivers/clocksource/rockchip_timer.c
@@ -19,7 +19,8 @@

  #define TIMER_LOAD_COUNT0	0x00
  #define TIMER_LOAD_COUNT1	0x04
-#define TIMER_CONTROL_REG	0x10
+#define TIMER_CONTROL_REG3288	0x10
+#define TIMER_CONTROL_REG3399	0x1C
  #define TIMER_INT_STATUS	0x18

  #define TIMER_DISABLE		0x0
@@ -31,6 +32,7 @@
  struct bc_timer {
  	struct clock_event_device ce;
  	void __iomem *base;
+	void __iomem *ctrl;
  	u32 freq;
  };

@@ -46,15 +48,20 @@ static inline void __iomem *rk_base(struct 
clock_event_device *ce)
  	return rk_timer(ce)->base;
  }

+static inline void __iomem *rk_ctrl(struct clock_event_device *ce)
+{
+        return rk_timer(ce)->ctrl;
+}
+
  static inline void rk_timer_disable(struct clock_event_device *ce)
  {
-	writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
+	writel_relaxed(TIMER_DISABLE, rk_ctrl(ce));
  }

  static inline void rk_timer_enable(struct clock_event_device *ce, u32 
flags)
  {
  	writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
-		       rk_base(ce) + TIMER_CONTROL_REG);
+		       rk_ctrl(ce));
  }

  static void rk_timer_update_counter(unsigned long cycles,
@@ -179,4 +186,18 @@ out_unmap:
  	iounmap(bc_timer.base);
  }

-CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
+static void __init rk3288_timer_init(struct device_node *np)
+{
+	bc_timer.ctrl = TIMER_CONTROL_REG3288;
+	rk_timer_init(np);
+}
+
+static void __init rk3399_timer_init(struct device_node *np)
+{
+        bc_timer.ctrl = TIMER_CONTROL_REG3399;
+	rk_timer_init(np);
+}
+
+
+CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", 
rk3288_timer_init);
+CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3399-timer", 
rk3399_timer_init);




-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog



From frank.wang at rock-chips.com  Mon May 30 23:40:10 2016
From: frank.wang at rock-chips.com (Frank Wang)
Date: Tue, 31 May 2016 14:40:10 +0800
Subject: [PATCH 1/2] Documentation: bindings: add DT documentation for
 Rockchip USB2PHY
In-Reply-To: <1464676811-7418-1-git-send-email-frank.wang@rock-chips.com>
References: <1464676811-7418-1-git-send-email-frank.wang@rock-chips.com>
Message-ID: <1464676811-7418-2-git-send-email-frank.wang@rock-chips.com>

Signed-off-by: Frank Wang <frank.wang at rock-chips.com>
---
 .../bindings/phy/phy-rockchip-inno-usb2.txt        |   48 ++++++++++++++++++++
 1 file changed, 48 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt

diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
new file mode 100644
index 0000000..4e537b2
--- /dev/null
+++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
@@ -0,0 +1,48 @@
+ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK
+
+Required properties (phy (parent) node):
+ - compatible: should contain:
+	* "rockchip,rk3366-usb2phy"
+ - #clock-cells: should be 0.
+ - clock-names: specify the 480m output clk name.
+
+Optional properties:
+ - vbus_host-gpio: pull gpio high/low to control the host vbus power.
+
+Required nodes: a sub-node is required for each port the phy provides.
+		The sub-node name is used to identify host or otg port.
+
+Required properties (port (child) node):
+ - #phy-cells: must be 0. See ./phy-bindings.txt for details.
+ - interrupts: irq number for host/otg port.
+ - interrupt-names: interrupt name, in line with irq number.
+
+Example:
+
+grf: syscon at ff770000 {
+	compatible = "rockchip,rk3366-grf", "syscon", "simple-mfd";
+	#address-cells = <1>;
+	#size-cells = <1>;
+
+...
+
+	u2phy: usb2-phy {
+		compatible = "rockchip,rk3366-usb2phy";
+		#clock-cells = <0>;
+		clock-output-names = "sclk_otgphy0_480m";
+
+		u2phy_otg: otg-port {
+			#phy-cells = <0>;
+			interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "linestate";
+			status = "okay";
+		};
+
+		u2phy_host: host-port {
+			#phy-cells = <0>;
+			interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+			interrupt-names = "linestate";
+			status = "okay";
+		};
+	};
+};
-- 
1.7.9.5




From frank.wang at rock-chips.com  Mon May 30 23:40:09 2016
From: frank.wang at rock-chips.com (Frank Wang)
Date: Tue, 31 May 2016 14:40:09 +0800
Subject: [PATCH 0/2] Add a new Rockchip usb2 phy driver
Message-ID: <1464676811-7418-1-git-send-email-frank.wang@rock-chips.com>

The newer SoCs (rk3366, rk3399) of Rock-chip take a different usb-phy
IP block than rk3288 and before, and most of phy-related registers are
also different from the past, so a new phy driver is required necessarily.

These series patches add phy-rockchip-inno-usb2.c and the corresponding
documentation.

Frank Wang (2):
  Documentation: bindings: add DT documentation for Rockchip USB2PHY
  phy: rockchip-inno-usb2: add a new driver for Rockchip usb2phy

 .../bindings/phy/phy-rockchip-inno-usb2.txt        |   48 ++
 drivers/phy/Kconfig                                |    7 +
 drivers/phy/Makefile                               |    1 +
 drivers/phy/phy-rockchip-inno-usb2.c               |  581 ++++++++++++++++++++
 4 files changed, 637 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
 create mode 100644 drivers/phy/phy-rockchip-inno-usb2.c

-- 
1.7.9.5




From frank.wang at rock-chips.com  Mon May 30 23:40:11 2016
From: frank.wang at rock-chips.com (Frank Wang)
Date: Tue, 31 May 2016 14:40:11 +0800
Subject: [PATCH 2/2] phy: rockchip-inno-usb2: add a new driver for Rockchip
 usb2phy
In-Reply-To: <1464676811-7418-1-git-send-email-frank.wang@rock-chips.com>
References: <1464676811-7418-1-git-send-email-frank.wang@rock-chips.com>
Message-ID: <1464676811-7418-3-git-send-email-frank.wang@rock-chips.com>

The newer SoCs (rk3366, rk3399) take a different usb-phy IP block
than rk3288 and before, and most of phy-related registers are also
different from the past, so a new phy driver is required necessarily.

Signed-off-by: Frank Wang <frank.wang at rock-chips.com>
---
 drivers/phy/Kconfig                  |    7 +
 drivers/phy/Makefile                 |    1 +
 drivers/phy/phy-rockchip-inno-usb2.c |  581 ++++++++++++++++++++++++++++++++++
 3 files changed, 589 insertions(+)
 create mode 100644 drivers/phy/phy-rockchip-inno-usb2.c

diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
index b869b98..29ef15c 100644
--- a/drivers/phy/Kconfig
+++ b/drivers/phy/Kconfig
@@ -347,6 +347,13 @@ config PHY_ROCKCHIP_USB
 	help
 	  Enable this to support the Rockchip USB 2.0 PHY.
 
+config PHY_ROCKCHIP_INNO_USB2
+	tristate "Rockchip INNO USB2PHY Driver"
+	depends on ARCH_ROCKCHIP && OF
+	select GENERIC_PHY
+	help
+	  Support for Rockchip USB2.0 PHY with Innosilicon IP block.
+
 config PHY_ROCKCHIP_EMMC
 	tristate "Rockchip EMMC PHY Driver"
 	depends on ARCH_ROCKCHIP && OF
diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
index 9c3e73c..4963fbc 100644
--- a/drivers/phy/Makefile
+++ b/drivers/phy/Makefile
@@ -38,6 +38,7 @@ phy-exynos-usb2-$(CONFIG_PHY_S5PV210_USB2)	+= phy-s5pv210-usb2.o
 obj-$(CONFIG_PHY_EXYNOS5_USBDRD)	+= phy-exynos5-usbdrd.o
 obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)	+= phy-qcom-apq8064-sata.o
 obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
+obj-$(CONFIG_PHY_ROCKCHIP_INNO_USB2)	+= phy-rockchip-inno-usb2.o
 obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
 obj-$(CONFIG_PHY_ROCKCHIP_DP)		+= phy-rockchip-dp.o
 obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)	+= phy-qcom-ipq806x-sata.o
diff --git a/drivers/phy/phy-rockchip-inno-usb2.c b/drivers/phy/phy-rockchip-inno-usb2.c
new file mode 100644
index 0000000..eeb5638
--- /dev/null
+++ b/drivers/phy/phy-rockchip-inno-usb2.c
@@ -0,0 +1,581 @@
+/*
+ * Rockchip USB2.0 PHY with Innosilicon IP block driver
+ *
+ * Copyright (C) 2016 Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/gpio/consumer.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+#include <linux/phy/phy.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+
+#define BIT_WRITEABLE_SHIFT	16
+#define SCHEDULE_DELAY	(60 * HZ)
+
+enum rockchip_usb2phy_port_id {
+	USB2PHY_PORT_OTG,
+	USB2PHY_PORT_HOST,
+	USB2PHY_NUM_PORTS,
+};
+
+enum rockchip_usb2phy_host_state {
+	PHY_STATE_HS_ONLINE	= 0,
+	PHY_STATE_DISCONNECT	= 1,
+	PHY_STATE_HS_CONNECT	= 2,
+	PHY_STATE_FS_CONNECT	= 4,
+};
+
+struct usb2phy_reg {
+	unsigned int	offset;
+	unsigned int	bitend;
+	unsigned int	bitstart;
+	unsigned int	disable;
+	unsigned int	enable;
+};
+
+/**
+ * struct rockchip_usb2phy_port_cfg: usb-phy port configuration.
+ * @phy_sus: phy suspend register.
+ * @ls_det_en: linestate detection enable register.
+ * @ls_det_st: linestate detection state register.
+ * @ls_det_clr: linestate detection clear register.
+ * @utmi_ls: utmi linestate state register.
+ * @utmi_hstdet: utmi host disconnect register.
+ */
+struct rockchip_usb2phy_port_cfg {
+	struct usb2phy_reg	phy_sus;
+	struct usb2phy_reg	ls_det_en;
+	struct usb2phy_reg	ls_det_st;
+	struct usb2phy_reg	ls_det_clr;
+	struct usb2phy_reg	utmi_ls;
+	struct usb2phy_reg	utmi_hstdet;
+};
+
+/**
+ * struct rockchip_usb2phy_cfg: usb-phy configuration.
+ * @num_ports: specify how many ports that the phy has.
+ * @clkout_ctl: keep on/turn off output clk of phy.
+ */
+struct rockchip_usb2phy_cfg {
+	unsigned int	num_ports;
+	struct usb2phy_reg	clkout_ctl;
+	const struct rockchip_usb2phy_port_cfg	*port_cfgs;
+};
+
+/**
+ * struct rockchip_usb2phy_port: usb-phy port data.
+ * @port_id: flag for otg port or host port.
+ * @suspended: phy suspended flag.
+ * @ls_irq: IRQ number assigned for linestate detection.
+ * @mutex: for register updating in sm_work.
+ * @sm_work: OTG state machine work.
+ * @phy_cfg: port register configuration, assigned by driver data.
+ */
+struct rockchip_usb2phy_port {
+	struct phy	*phy;
+	unsigned int	port_id;
+	bool		suspended;
+	int		ls_irq;
+	struct mutex	mutex;
+	struct		delayed_work sm_work;
+	const struct	rockchip_usb2phy_port_cfg *port_cfg;
+};
+
+/**
+ * struct rockchip_usb2phy: usb2.0 phy driver data.
+ * @grf: General Register Files regmap.
+ * @clk480m: clock struct of phy output clk.
+ * @clk_hw: clock struct of phy output clk management.
+ * @vbus_host_gpio: host VBUS direction output.
+ * @phy_cfg: phy register configuration, assigned by driver data.
+ * @ports: phy port instance.
+ */
+struct rockchip_usb2phy {
+	struct device	*dev;
+	struct regmap	*grf;
+	struct clk	*clk480m;
+	struct clk_hw	clk480m_hw;
+	struct gpio_desc	*vbus_host_gpio;
+	const struct rockchip_usb2phy_cfg	*phy_cfg;
+	struct rockchip_usb2phy_port	ports[USB2PHY_NUM_PORTS];
+};
+
+static inline int property_enable(struct rockchip_usb2phy *rphy,
+				  const struct usb2phy_reg *reg, bool en)
+{
+	unsigned int val, mask, tmp;
+
+	tmp = en ? reg->enable : reg->disable;
+	mask = GENMASK(reg->bitend, reg->bitstart);
+	val = (tmp << reg->bitstart) | (mask << BIT_WRITEABLE_SHIFT);
+
+	return regmap_write(rphy->grf, reg->offset, val);
+}
+
+static inline bool property_enabled(struct rockchip_usb2phy *rphy,
+				    const struct usb2phy_reg *reg)
+{
+	int ret;
+	unsigned int tmp, orig;
+	unsigned int mask = GENMASK(reg->bitend, reg->bitstart);
+
+	ret = regmap_read(rphy->grf, reg->offset, &orig);
+	if (ret)
+		return false;
+
+	tmp = (orig & mask) >> reg->bitstart;
+	return tmp == reg->enable;
+}
+
+static int rockchip_usb2phy_clk480m_enable(struct clk_hw *hw)
+{
+	struct rockchip_usb2phy *rphy =
+		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
+	int ret = 0;
+
+	/* turn on 480m clk output if it is off */
+	if (!property_enabled(rphy, &rphy->phy_cfg->clkout_ctl)) {
+		ret = property_enable(rphy, &rphy->phy_cfg->clkout_ctl, true);
+		if (ret)
+			return ret;
+
+		/* waitting for the clk become stable */
+		mdelay(1);
+	}
+
+	return ret;
+}
+
+static void rockchip_usb2phy_clk480m_disable(struct clk_hw *hw)
+{
+	struct rockchip_usb2phy *rphy =
+		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
+	int index;
+
+	/* make sure all ports in suspended mode */
+	for (index = 0; index != rphy->phy_cfg->num_ports; index++)
+		if (!rphy->ports[index].suspended)
+			return;
+
+	/* turn off 480m clk output */
+	property_enable(rphy, &rphy->phy_cfg->clkout_ctl, false);
+}
+
+static int rockchip_usb2phy_clk480m_enabled(struct clk_hw *hw)
+{
+	struct rockchip_usb2phy *rphy =
+		container_of(hw, struct rockchip_usb2phy, clk480m_hw);
+
+	return property_enabled(rphy, &rphy->phy_cfg->clkout_ctl);
+}
+
+static unsigned long
+rockchip_usb2phy_clk480m_recalc_rate(struct clk_hw *hw,
+				     unsigned long parent_rate)
+{
+	return 480000000;
+}
+
+static const struct clk_ops rockchip_usb2phy_clkout_ops = {
+	.enable = rockchip_usb2phy_clk480m_enable,
+	.disable = rockchip_usb2phy_clk480m_disable,
+	.is_enabled = rockchip_usb2phy_clk480m_enabled,
+	.recalc_rate = rockchip_usb2phy_clk480m_recalc_rate,
+};
+
+static struct clk *
+rockchip_usb2phy_clk480m_register(struct rockchip_usb2phy *rphy)
+{
+	struct device_node *node = rphy->dev->of_node;
+	struct clk *clk;
+	struct clk_init_data init;
+
+	init.name = "clk_usbphy_480m";
+	init.ops = &rockchip_usb2phy_clkout_ops;
+	init.flags = CLK_IS_ROOT;
+	init.parent_names = NULL;
+	init.num_parents = 0;
+	rphy->clk480m_hw.init = &init;
+
+	/* optional override of the clockname */
+	of_property_read_string(node, "clock-output-names", &init.name);
+
+	/* register the clock */
+	clk = clk_register(rphy->dev, &rphy->clk480m_hw);
+	if (!IS_ERR(clk))
+		of_clk_add_provider(node, of_clk_src_simple_get, clk);
+
+	return clk;
+}
+
+static int rockchip_usb2phy_init(struct phy *phy)
+{
+	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
+	int ret = 0;
+
+	if (rport->port_id == USB2PHY_PORT_HOST) {
+		/* clear linestate and enable linestate detect irq */
+		mutex_lock(&rport->mutex);
+
+		ret = property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
+		if (ret) {
+			mutex_unlock(&rport->mutex);
+			return ret;
+		}
+
+		ret = property_enable(rphy, &rport->port_cfg->ls_det_en, true);
+		if (ret) {
+			mutex_unlock(&rport->mutex);
+			return ret;
+		}
+
+		mutex_unlock(&rport->mutex);
+		schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY);
+	}
+
+	return ret;
+}
+
+static int rockchip_usb2phy_resume(struct phy *phy)
+{
+	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
+	int ret;
+
+	dev_dbg(&rport->phy->dev, "port resume\n");
+
+	ret = clk_prepare_enable(rphy->clk480m);
+	if (ret)
+		return ret;
+
+	ret = property_enable(rphy, &rport->port_cfg->phy_sus, false);
+	if (ret)
+		return ret;
+
+	rport->suspended = false;
+	return 0;
+}
+
+static int rockchip_usb2phy_suspend(struct phy *phy)
+{
+	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(phy->dev.parent);
+	int ret;
+
+	dev_dbg(&rport->phy->dev, "port suspend\n");
+
+	ret = property_enable(rphy, &rport->port_cfg->phy_sus, true);
+	if (ret)
+		return ret;
+
+	rport->suspended = true;
+	clk_disable_unprepare(rphy->clk480m);
+	return 0;
+}
+
+static int rockchip_usb2phy_exit(struct phy *phy)
+{
+	struct rockchip_usb2phy_port *rport = phy_get_drvdata(phy);
+
+	if (rport->port_id == USB2PHY_PORT_HOST)
+		cancel_delayed_work_sync(&rport->sm_work);
+
+	return 0;
+}
+
+static const struct phy_ops rockchip_usb2phy_ops = {
+	.init		= rockchip_usb2phy_init,
+	.exit		= rockchip_usb2phy_exit,
+	.power_on	= rockchip_usb2phy_resume,
+	.power_off	= rockchip_usb2phy_suspend,
+	.owner		= THIS_MODULE,
+};
+
+/*
+ * The function manage host-phy port state and suspend/resume phy port
+ * to save power.
+ *
+ * we rely on utmi_linestate and utmi_hostdisconnect to identify whether
+ * FS/HS is disconnect or not. Besides, we do not need care it is FS
+ * disconnected or HS disconnected, actually, we just only need get the
+ * device is disconnected at last through rearm the delayed work,
+ * to suspend the phy port in _PHY_STATE_DISCONNECT_ case.
+ *
+ * NOTE: It will invoke some clk related APIs, so do not invoke it from
+ * interrupt context.
+ */
+static void rockchip_usb2phy_sm_work(struct work_struct *work)
+{
+	struct rockchip_usb2phy_port *rport =
+		container_of(work, struct rockchip_usb2phy_port, sm_work.work);
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+	unsigned int sh = rport->port_cfg->utmi_hstdet.bitend -
+			  rport->port_cfg->utmi_hstdet.bitstart + 1;
+	unsigned int ul, uhd, state;
+	unsigned int ul_mask, uhd_mask;
+	int ret;
+
+	mutex_lock(&rport->mutex);
+
+	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_ls.offset, &ul);
+	if (ret < 0)
+		goto next_schedule;
+
+	ret = regmap_read(rphy->grf, rport->port_cfg->utmi_hstdet.offset,
+			  &uhd);
+	if (ret < 0)
+		goto next_schedule;
+
+	uhd_mask = GENMASK(rport->port_cfg->utmi_hstdet.bitend,
+			   rport->port_cfg->utmi_hstdet.bitstart);
+	ul_mask = GENMASK(rport->port_cfg->utmi_ls.bitend,
+			  rport->port_cfg->utmi_ls.bitstart);
+
+	/* stitch on utmi_ls and utmi_hstdet as phy state */
+	state = ((uhd & uhd_mask) >> rport->port_cfg->utmi_hstdet.bitstart) |
+		(((ul & ul_mask) >> rport->port_cfg->utmi_ls.bitstart) << sh);
+
+	switch (state) {
+	case PHY_STATE_HS_ONLINE:
+		dev_dbg(&rport->phy->dev, "HS online\n");
+		break;
+	case PHY_STATE_FS_CONNECT:
+		/*
+		 * For FS device, the online state share with connect state
+		 * from utmi_ls and utmi_hstdet register, so we distinguish
+		 * them via suspended flag.
+		 */
+		if (!rport->suspended) {
+			dev_dbg(&rport->phy->dev, "FS online\n");
+			break;
+		}
+		/* fall through */
+	case PHY_STATE_HS_CONNECT:
+		if (rport->suspended) {
+			dev_dbg(&rport->phy->dev, "HS/FS connected\n");
+			rockchip_usb2phy_resume(rport->phy);
+			rport->suspended = false;
+		}
+		break;
+	case PHY_STATE_DISCONNECT:
+		if (!rport->suspended) {
+			dev_dbg(&rport->phy->dev, "HS/FS disconnected\n");
+			rockchip_usb2phy_suspend(rport->phy);
+			rport->suspended = true;
+		}
+
+		/*
+		 * activate the linestate detection to get the next device
+		 * plug-in irq.
+		 */
+		property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
+		property_enable(rphy, &rport->port_cfg->ls_det_en, true);
+
+		/*
+		 * we don't need to rearm the delayed work when the phy port
+		 * is suspended.
+		 */
+		mutex_unlock(&rport->mutex);
+		return;
+	default:
+		dev_dbg(&rport->phy->dev, "unknown phy state\n");
+		break;
+	}
+
+next_schedule:
+	mutex_unlock(&rport->mutex);
+	schedule_delayed_work(&rport->sm_work, SCHEDULE_DELAY);
+}
+
+static irqreturn_t rockchip_usb2phy_linestate_irq(int irq, void *data)
+{
+	struct rockchip_usb2phy_port *rport = data;
+	struct rockchip_usb2phy *rphy = dev_get_drvdata(rport->phy->dev.parent);
+
+	if (!property_enabled(rphy, &rport->port_cfg->ls_det_st))
+		return IRQ_NONE;
+
+	mutex_lock(&rport->mutex);
+
+	/* disable linestate detect irq and clear its status */
+	property_enable(rphy, &rport->port_cfg->ls_det_en, false);
+	property_enable(rphy, &rport->port_cfg->ls_det_clr, true);
+
+	mutex_unlock(&rport->mutex);
+
+	/*
+	 * In this case for host phy port, a new device is plugged in,
+	 * meanwhile, if the phy port is suspended, we need rearm the work to
+	 * resume it and mange its states; otherwise, we do nothing about that.
+	 */
+	if (rport->suspended && rport->port_id == USB2PHY_PORT_HOST)
+		rockchip_usb2phy_sm_work(&rport->sm_work.work);
+
+	return IRQ_HANDLED;
+}
+
+static int rockchip_usb2phy_host_port_init(struct rockchip_usb2phy *rphy,
+					   struct rockchip_usb2phy_port *rport,
+					   struct device_node *child_np)
+{
+	int ret = 0;
+
+	rport->port_id = USB2PHY_PORT_HOST;
+	mutex_init(&rport->mutex);
+	INIT_DELAYED_WORK(&rport->sm_work, rockchip_usb2phy_sm_work);
+
+	rport->ls_irq = of_irq_get_byname(child_np, "linestate");
+	if (rport->ls_irq < 0) {
+		dev_err(rphy->dev, "no linestate irq provided\n");
+		return rport->ls_irq;
+	}
+
+	ret = devm_request_threaded_irq(rphy->dev, rport->ls_irq, NULL,
+					rockchip_usb2phy_linestate_irq,
+					IRQF_ONESHOT,
+					"rockchip_usb2phy", rport);
+	if (ret) {
+		dev_err(rphy->dev, "failed to request irq handle\n");
+		return ret;
+	}
+
+	return ret;
+}
+
+static int rockchip_usb2phy_probe(struct platform_device *pdev)
+{
+	struct device *dev = &pdev->dev;
+	struct device_node *np = dev->of_node;
+	struct device_node *child_np;
+	struct phy_provider *provider;
+	struct rockchip_usb2phy *rphy;
+	const struct of_device_id *match;
+	int index, ret;
+
+	rphy = devm_kzalloc(dev, sizeof(*rphy), GFP_KERNEL);
+	if (!rphy)
+		return -ENOMEM;
+
+	match = of_match_device(dev->driver->of_match_table, dev);
+	if (!match || !match->data) {
+		dev_err(dev, "phy configs are not assigned!\n");
+		return -EINVAL;
+	}
+
+	if (!dev->parent || !dev->parent->of_node)
+		return -ENOMEM;
+
+	rphy->grf = syscon_node_to_regmap(dev->parent->of_node);
+	if (IS_ERR(rphy->grf))
+		return PTR_ERR(rphy->grf);
+
+	rphy->dev = dev;
+	rphy->phy_cfg = match->data;
+	platform_set_drvdata(pdev, rphy);
+
+	rphy->clk480m = rockchip_usb2phy_clk480m_register(rphy);
+	if (IS_ERR(rphy->clk480m))
+		return PTR_ERR(rphy->clk480m);
+
+	rphy->vbus_host_gpio =
+		devm_gpiod_get_optional(dev, "vbus_host", GPIOD_OUT_HIGH);
+	if (!rphy->vbus_host_gpio)
+		dev_info(dev, "host_vbus is not assigned!\n");
+	else if (IS_ERR(rphy->vbus_host_gpio))
+		return PTR_ERR(rphy->vbus_host_gpio);
+
+	index = 0;
+	for_each_child_of_node(np, child_np) {
+		struct rockchip_usb2phy_port *rport = &rphy->ports[index];
+		struct phy *phy;
+
+		phy = devm_phy_create(dev, child_np, &rockchip_usb2phy_ops);
+		if (IS_ERR(phy)) {
+			dev_err(dev, "failed to create phy\n");
+			ret = PTR_ERR(phy);
+			goto put_child;
+		}
+
+		rport->phy = phy;
+		rport->port_cfg = &rphy->phy_cfg->port_cfgs[index];
+
+		/* initialize otg/host port separately */
+		if (!of_node_cmp(child_np->name, "host-port")) {
+			ret = rockchip_usb2phy_host_port_init(rphy, rport,
+							      child_np);
+			if (ret)
+				goto put_child;
+		}
+
+		phy_set_drvdata(rport->phy, rport);
+		index++;
+	}
+
+	provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
+	return PTR_ERR_OR_ZERO(provider);
+
+put_child:
+	of_node_put(child_np);
+	of_clk_del_provider(np);
+	clk_unregister(rphy->clk480m);
+	return ret;
+}
+
+static const struct rockchip_usb2phy_cfg rk3366_phy_cfgs = {
+	.num_ports	= 1,
+	.clkout_ctl	= { 0x0724, 15, 15, 1, 0 },
+	.port_cfgs	= (struct rockchip_usb2phy_port_cfg[]) {
+		{
+			.phy_sus	= { 0x0728, 15, 0, 0, 0x1d1 },
+			.ls_det_en	= { 0x0680, 4, 4, 0, 1 },
+			.ls_det_st	= { 0x0690, 4, 4, 0, 1 },
+			.ls_det_clr	= { 0x06a0, 4, 4, 0, 1 },
+			.utmi_ls	= { 0x049c, 14, 13, 0, 1 },
+			.utmi_hstdet	= { 0x049c, 12, 12, 0, 1 }
+		},
+		{ /* sentinel */ }
+	},
+};
+
+static const struct of_device_id rockchip_usb2phy_dt_match[] = {
+	{ .compatible = "rockchip,rk3366-usb2phy", .data = &rk3366_phy_cfgs },
+	{}
+};
+MODULE_DEVICE_TABLE(of, rockchip_usb2phy_dt_match);
+
+static struct platform_driver rockchip_usb2phy_driver = {
+	.probe		= rockchip_usb2phy_probe,
+	.driver		= {
+		.name	= "rockchip-usb2phy",
+		.of_match_table = rockchip_usb2phy_dt_match,
+	},
+};
+module_platform_driver(rockchip_usb2phy_driver);
+
+MODULE_AUTHOR("Frank Wang <frank.wang at rock-chips.com>");
+MODULE_DESCRIPTION("Rockchip USB2.0 PHY driver");
+MODULE_LICENSE("GPL v2");
-- 
1.7.9.5




From heiko at sntech.de  Tue May 31 02:02:12 2016
From: heiko at sntech.de (Heiko =?ISO-8859-1?Q?St=FCbner?=)
Date: Tue, 31 May 2016 11:02:12 +0200
Subject: [PATCH 1/2] Documentation: bindings: add DT documentation for
 Rockchip USB2PHY
In-Reply-To: <1464676811-7418-2-git-send-email-frank.wang@rock-chips.com>
References: <1464676811-7418-1-git-send-email-frank.wang@rock-chips.com>
 <1464676811-7418-2-git-send-email-frank.wang@rock-chips.com>
Message-ID: <6548390.RQDBBuPzBf@diego>

Hi Frank,

Am Dienstag, 31. Mai 2016, 14:40:10 schrieb Frank Wang:
> Signed-off-by: Frank Wang <frank.wang at rock-chips.com>
> ---
>  .../bindings/phy/phy-rockchip-inno-usb2.txt        |   48
> ++++++++++++++++++++ 1 file changed, 48 insertions(+)
>  create mode 100644
> Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
> 
> diff --git
> a/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
> b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt new file
> mode 100644
> index 0000000..4e537b2
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-inno-usb2.txt
> @@ -0,0 +1,48 @@
> +ROCKCHIP USB2.0 PHY WITH INNO IP BLOCK
> +
> +Required properties (phy (parent) node):
> + - compatible: should contain:
> +	* "rockchip,rk3366-usb2phy"
> + - #clock-cells: should be 0.
> + - clock-names: specify the 480m output clk name.
> +
> +Optional properties:
> + - vbus_host-gpio: pull gpio high/low to control the host vbus power.

sorry for not catching that in our earlier talks, but I believe this should be 
a regulator instead. See for example vcc5_host1, vcc5v_otg in rk3288-veyron-
chromebook.dtsi .


> +Required nodes: a sub-node is required for each port the phy provides.
> +		The sub-node name is used to identify host or otg port.
> +
> +Required properties (port (child) node):
> + - #phy-cells: must be 0. See ./phy-bindings.txt for details.
> + - interrupts: irq number for host/otg port.

make that something like:
Specify an interrupt for each entry in interrupt-names.

> + - interrupt-names: interrupt name, in line with irq number.

make that something like:
Shall be "linestate" for the linestate interrupt.
---

You might want to add the bvalid and id interrupts for the otg phys as well 
already - would make handling legacy devicetree files easier. [= if they get 
specified later, the driver would always need to also handle devicetrees where 
they aren't specified].


Heiko


From shawn.lin at kernel-upstream.org  Tue May 31 02:48:10 2016
From: shawn.lin at kernel-upstream.org (Shawn Lin)
Date: Tue, 31 May 2016 17:48:10 +0800
Subject: [PATCH 1/2] Documentation: add binding description of Rockchip
 PCIe controller
In-Reply-To: <20160530120836.290f0d16@arm.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740146-7106-1-git-send-email-shawn.lin@rock-chips.com>
 <20160530120836.290f0d16@arm.com>
Message-ID: <c6fa65a1-58bd-520a-42a1-d6edf576840a@kernel-upstream.org>

Hi Marc,

? 2016/5/30 19:08, Marc Zyngier ??:
> On Fri, 20 May 2016 18:29:06 +0800
> Shawn Lin <shawn.lin at rock-chips.com> wrote:
>
>> This patch add some required and optional properties for Rockchip
>> PCIe controller. Also we add a example for how to use it.
>>
>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>
>> ---
>>
>>  .../devicetree/bindings/pci/rockchip-pcie.txt      | 93 ++++++++++++++++++++++
>>  1 file changed, 93 insertions(+)
>>  create mode 100644 Documentation/devicetree/bindings/pci/rockchip-pcie.txt
>>
>> diff --git a/Documentation/devicetree/bindings/pci/rockchip-pcie.txt b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
>> new file mode 100644
>> index 0000000..69a0804
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
>> @@ -0,0 +1,93 @@
>> +* Rockchip AXI PCIe Root Port Bridge DT description
>> +
>> +Required properties:
>> +- #address-cells: Address representation for root ports, set to <3>
>> +- #size-cells: Size representation for root ports, set to <2>
>> +- #interrupt-cells: specifies the number of cells needed to encode an
>> +		interrupt source. The value must be 1.
>> +- compatible: Should contain "rockchip,rk3399-pcie"
>> +- reg: Two register ranges as listed in the reg-names property
>> +- reg-names: The first entry must be "axi-base" for the core registers
>> +	The second entry must be "apb-base" for the client pcie registers
>> +- clocks: Must contain an entry for each entry in clock-names.
>> +		See ../clocks/clock-bindings.txt for details.
>> +- clock-names: Must include the following entries:
>> +	- "aclk_pcie"
>> +	- "aclk_perf_pcie"
>> +	- "hclk_pcie"
>> +	- "clk_pciephy_ref"
>> +- interrupts: Three interrupt entries must be specified.
>> +- interrupt-names: Must include the following names
>> +	- "pcie-sys"
>> +	- "pcie-legacy"
>> +	- "pcie-client"
>> +- resets: Must contain five entries for each entry in reset-names.
>> +	   See ../reset/reset.txt for details.
>> +- reset-names: Must include the following names
>> +	- "phy-rst"
>> +	- "core-rst"
>> +	- "mgmt-rst"
>> +	- "mgmt-sticky-rst"
>> +	- "pipe-rst"
>> +- rockchip,grf: phandle to the syscon managing the "general register files"
>> +- pcie-conf: offset of pcie client block for  configuration
>> +- pcie-status: offset of pcie client block for status
>> +- pcie-laneoff: offset of pcie client block for lane
>> +- msi-parent: Link to the hardware entity that serves as the Message
>> +- pinctrl-names : The pin control state names
>> +- pinctrl-0: The "default" pinctrl state
>> +- interrupt-map-mask and interrupt-map: standard PCI properties
>> +- interrupt-controller: identifies the node as an interrupt controller
>> +
>> +Optional Property:
>> +- ep-gpios: contain the entry for pre-reset gpio
>> +- num-lanes: number of lanes to use
>> +- assigned-clocks, assigned-clock-parents and assigned-clock-rates: standard
>> +		   clock bindings. See ../clock/clock-bindings.txt
>> +
>> +Example:
>> +
>> +pci_express: axi-pcie at f8000000 {
>> +	#address-cells = <3>;
>> +	#size-cells = <2>;
>> +	compatible = "rockchip,rk3399-pcie";
>> +	clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>,
>> +		 <&cru PCLK_PCIE>, <&cru SCLK_PCIEPHY_REF>;
>> +	clock-names = "aclk_pcie", "aclk_perf_pcie",
>> +		      "hclk_pcie", "clk_pciephy_ref";
>> +	bus-range = <0x0 0x1>;
>> +	interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>,
>> +		     <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
>> +	interrupt-names: "pcie-sys", "pcie-legacy", "pcie-client";
>> +	assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
>> +	assigned-clock-parents = <&cru SCLK_PCIEPHY_REF100M>;
>> +	assigned-clock-rates = <100000000>;
>> +	ep-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
>> +	ranges = < 0x82000000 0 0xfa000000 0x0 0xfa000000 0 0x600000
>> +		   0x81000000 0 0xfa600000 0x0 0xfa600000 0 0x100000 >;
>> +	num-lanes = <4>;
>> +	reg = < 0x0 0xf8000000 0x0 0x2000000 >, < 0x0 0xfd000000 0x0 0x1000000 >;
>> +	reg-name = "axi-base", "apb-base";
>> +	resets = <&cru SRST_PCIEPHY>, <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>,
>> +		 <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>;
>> +	reset-names = "phy-rst", "core-rst", "mgmt-rst", "mgmt-sticky-rst", "pipe-rst";
>> +	rockchip,grf = <&grf>;
>> +	pcie-conf = <0xe220>;
>> +	pcie-status = <0xe2a4>;
>> +	pcie-laneoff = <0xe214>;
>> +	pinctrl-names = "default";
>> +	pinctrl-0 = <&pcie_clkreq>;
>> +	msi-parent = <&its>;
>
> We've moved away from bare msi-parent for the ITS (notice that the
> binding mandates #msi-cells = <1>). So what you need here is an msi-map
> (as described in Documentation/devicetree/bindings/pci/pci-msi.txt).
>
> Do you have an IOMMU (or some other remapping HW) between the RC and the
> GIC ITS? If so, yo may have to describe the mappings between the PCIe
> RID and the ITS DevID in this msi-map.
>

yes, we don't need msi-parent here. And we don't need msi-map as well,
since we don't have a IOMMU block between RC and ITS which need to be
described in msi-map.


Thanks.

>> +	#interrupt-cells = <1>;
>> +	interrupt-map-mask = <0 0 0 7>;
>> +	interrupt-map = <0 0 0 1 &pcie_0 1>,
>> +			<0 0 0 2 &pcie_0 2>,
>> +			<0 0 0 3 &pcie_0 3>,
>> +			<0 0 0 4 &pcie_0 4>;
>> +	pcie_0: interrupt-controller {
>> +		interrupt-controller;
>> +		#address-cells = <0>;
>> +		#interrupt-cells = <1>;
>> +	};
>> +
>> +};
>
> Thanks,
>
> 	M.
>



From marc.zyngier at arm.com  Tue May 31 03:09:43 2016
From: marc.zyngier at arm.com (Marc Zyngier)
Date: Tue, 31 May 2016 11:09:43 +0100
Subject: [PATCH 1/2] Documentation: add binding description of Rockchip
 PCIe controller
In-Reply-To: <c6fa65a1-58bd-520a-42a1-d6edf576840a@kernel-upstream.org>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740146-7106-1-git-send-email-shawn.lin@rock-chips.com>
 <20160530120836.290f0d16@arm.com>
 <c6fa65a1-58bd-520a-42a1-d6edf576840a@kernel-upstream.org>
Message-ID: <574D62E7.50404@arm.com>

On 31/05/16 10:48, Shawn Lin wrote:
> Hi Marc,
> 
> ? 2016/5/30 19:08, Marc Zyngier ??:
>> On Fri, 20 May 2016 18:29:06 +0800
>> Shawn Lin <shawn.lin at rock-chips.com> wrote:
>>
>>> This patch add some required and optional properties for Rockchip
>>> PCIe controller. Also we add a example for how to use it.
>>>
>>> Signed-off-by: Shawn Lin <shawn.lin at rock-chips.com>
>>>
>>> ---
>>>
>>>  .../devicetree/bindings/pci/rockchip-pcie.txt      | 93 ++++++++++++++++++++++
>>>  1 file changed, 93 insertions(+)
>>>  create mode 100644 Documentation/devicetree/bindings/pci/rockchip-pcie.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/pci/rockchip-pcie.txt b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
>>> new file mode 100644
>>> index 0000000..69a0804
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/pci/rockchip-pcie.txt
>>> @@ -0,0 +1,93 @@
>>> +* Rockchip AXI PCIe Root Port Bridge DT description
>>> +
>>> +Required properties:
>>> +- #address-cells: Address representation for root ports, set to <3>
>>> +- #size-cells: Size representation for root ports, set to <2>
>>> +- #interrupt-cells: specifies the number of cells needed to encode an
>>> +		interrupt source. The value must be 1.
>>> +- compatible: Should contain "rockchip,rk3399-pcie"
>>> +- reg: Two register ranges as listed in the reg-names property
>>> +- reg-names: The first entry must be "axi-base" for the core registers
>>> +	The second entry must be "apb-base" for the client pcie registers
>>> +- clocks: Must contain an entry for each entry in clock-names.
>>> +		See ../clocks/clock-bindings.txt for details.
>>> +- clock-names: Must include the following entries:
>>> +	- "aclk_pcie"
>>> +	- "aclk_perf_pcie"
>>> +	- "hclk_pcie"
>>> +	- "clk_pciephy_ref"
>>> +- interrupts: Three interrupt entries must be specified.
>>> +- interrupt-names: Must include the following names
>>> +	- "pcie-sys"
>>> +	- "pcie-legacy"
>>> +	- "pcie-client"
>>> +- resets: Must contain five entries for each entry in reset-names.
>>> +	   See ../reset/reset.txt for details.
>>> +- reset-names: Must include the following names
>>> +	- "phy-rst"
>>> +	- "core-rst"
>>> +	- "mgmt-rst"
>>> +	- "mgmt-sticky-rst"
>>> +	- "pipe-rst"
>>> +- rockchip,grf: phandle to the syscon managing the "general register files"
>>> +- pcie-conf: offset of pcie client block for  configuration
>>> +- pcie-status: offset of pcie client block for status
>>> +- pcie-laneoff: offset of pcie client block for lane
>>> +- msi-parent: Link to the hardware entity that serves as the Message
>>> +- pinctrl-names : The pin control state names
>>> +- pinctrl-0: The "default" pinctrl state
>>> +- interrupt-map-mask and interrupt-map: standard PCI properties
>>> +- interrupt-controller: identifies the node as an interrupt controller
>>> +
>>> +Optional Property:
>>> +- ep-gpios: contain the entry for pre-reset gpio
>>> +- num-lanes: number of lanes to use
>>> +- assigned-clocks, assigned-clock-parents and assigned-clock-rates: standard
>>> +		   clock bindings. See ../clock/clock-bindings.txt
>>> +
>>> +Example:
>>> +
>>> +pci_express: axi-pcie at f8000000 {
>>> +	#address-cells = <3>;
>>> +	#size-cells = <2>;
>>> +	compatible = "rockchip,rk3399-pcie";
>>> +	clocks = <&cru ACLK_PCIE>, <&cru ACLK_PERF_PCIE>,
>>> +		 <&cru PCLK_PCIE>, <&cru SCLK_PCIEPHY_REF>;
>>> +	clock-names = "aclk_pcie", "aclk_perf_pcie",
>>> +		      "hclk_pcie", "clk_pciephy_ref";
>>> +	bus-range = <0x0 0x1>;
>>> +	interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>,
>>> +		     <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
>>> +	interrupt-names: "pcie-sys", "pcie-legacy", "pcie-client";
>>> +	assigned-clocks = <&cru SCLK_PCIEPHY_REF>;
>>> +	assigned-clock-parents = <&cru SCLK_PCIEPHY_REF100M>;
>>> +	assigned-clock-rates = <100000000>;
>>> +	ep-gpios = <&gpio3 13 GPIO_ACTIVE_HIGH>;
>>> +	ranges = < 0x82000000 0 0xfa000000 0x0 0xfa000000 0 0x600000
>>> +		   0x81000000 0 0xfa600000 0x0 0xfa600000 0 0x100000 >;
>>> +	num-lanes = <4>;
>>> +	reg = < 0x0 0xf8000000 0x0 0x2000000 >, < 0x0 0xfd000000 0x0 0x1000000 >;
>>> +	reg-name = "axi-base", "apb-base";
>>> +	resets = <&cru SRST_PCIEPHY>, <&cru SRST_PCIE_CORE>, <&cru SRST_PCIE_MGMT>,
>>> +		 <&cru SRST_PCIE_MGMT_STICKY>, <&cru SRST_PCIE_PIPE>;
>>> +	reset-names = "phy-rst", "core-rst", "mgmt-rst", "mgmt-sticky-rst", "pipe-rst";
>>> +	rockchip,grf = <&grf>;
>>> +	pcie-conf = <0xe220>;
>>> +	pcie-status = <0xe2a4>;
>>> +	pcie-laneoff = <0xe214>;
>>> +	pinctrl-names = "default";
>>> +	pinctrl-0 = <&pcie_clkreq>;
>>> +	msi-parent = <&its>;
>>
>> We've moved away from bare msi-parent for the ITS (notice that the
>> binding mandates #msi-cells = <1>). So what you need here is an msi-map
>> (as described in Documentation/devicetree/bindings/pci/pci-msi.txt).
>>
>> Do you have an IOMMU (or some other remapping HW) between the RC and the
>> GIC ITS? If so, yo may have to describe the mappings between the PCIe
>> RID and the ITS DevID in this msi-map.
>>
> 
> yes, we don't need msi-parent here. And we don't need msi-map as well,
> since we don't have a IOMMU block between RC and ITS which need to be
> described in msi-map.

Well, if have neither msi-parent nor msi-map, you won't get MSI at all.

Maybe that's good enough for you, but in that case, make sure you drop
all the MSI code from your patches! ;-) More seriously, you do need an
msi-map, even if that's with a single entry.

Thanks,

	M.
-- 
Jazz is not dead. It just smells funny...


From ykk at rock-chips.com  Tue May 31 06:37:36 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 31 May 2016 21:37:36 +0800
Subject: [RFC PATCH v1 0/2] 
Message-ID: <1464701856-8695-1-git-send-email-ykk@rock-chips.com>

The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make a lots
of sense to save the power consumption.

For example, when desktop haven't change the context for a long time,
then we could refresh the data to the hardware framebuffer of panel,
and then let panel enter into PSR mode. After that system could poweroff
the LCDC controller and eDP controller, just let panel refresh the screen
by itself.

It's hard to decide when panel should enter into PSR or exit from PSR, in
this time I chose to let the drm_vblank enable/disable event driver the PSR.

This thread is based on Mark's RK3399 VOP thread[0] and my RK3399 eDP
thread[1].

[0]: https://patchwork.kernel.org/patch/8886041/
[1]: https://patchwork.kernel.org/patch/9132713/

- Yakir
Thanks,


Yakir Yang (2):
  drm/rockchip: add a notify event about vblank enable/disable
  drm/rockchip: analogix: add eDP PSR function

 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  69 ++++++++++++++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |   5 +
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  |  54 +++++++++++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  |  28 ++++++
 drivers/gpu/drm/rockchip/Makefile                  |   2 +-
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    |  65 +++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_notify.c     | 105 +++++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_notify.h     |  33 +++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |  96 +++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h        |   3 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c        |   2 +
 include/drm/bridge/analogix_dp.h                   |   3 +
 12 files changed, 464 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.h

-- 
1.9.1




From ykk at rock-chips.com  Tue May 31 06:39:19 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 31 May 2016 21:39:19 +0800
Subject: [RFC PATCH v1 1/2] drm/rockchip: add a notify event about vblank
 enable/disable
In-Reply-To: <1464701856-8695-1-git-send-email-ykk@rock-chips.com>
References: <1464701856-8695-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464701959-9428-1-git-send-email-ykk@rock-chips.com>

EDP PSR function is interesting in vblank enable or disable event,
so it would be great introduce a way to notify encoder about this
event.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 drivers/gpu/drm/rockchip/Makefile              |  2 +-
 drivers/gpu/drm/rockchip/rockchip_drm_notify.c | 66 ++++++++++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_notify.h | 29 +++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c    |  5 ++
 4 files changed, 101 insertions(+), 1 deletion(-)
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.c
 create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.h

diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
index 05d0713..49fee8c 100644
--- a/drivers/gpu/drm/rockchip/Makefile
+++ b/drivers/gpu/drm/rockchip/Makefile
@@ -3,7 +3,7 @@
 # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
 
 rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
-		rockchip_drm_gem.o rockchip_drm_vop.o
+		rockchip_drm_gem.o rockchip_drm_vop.o rockchip_drm_notify.o
 rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
 
 obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.c b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c
new file mode 100644
index 0000000..84111d9
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c
@@ -0,0 +1,66 @@
+#include "rockchip_drm_notify.h"
+
+static RAW_NOTIFIER_HEAD(vblank_chain);
+static DEFINE_MUTEX(vblank_lock);
+
+/**
+ * rockchip_drm_vblank_enable - Send Vblank enable event. Will only enable send
+ * Vblank if there are 1 or fewer notifiers.
+ */
+void rockchip_drm_vblank_enable(void)
+{
+	mutex_lock(&vblank_lock);
+	raw_notifier_call_chain(&vblank_chain, VBLANK_ENABLE, NULL);
+	mutex_unlock(&vblank_lock);
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_vblank_enable);
+
+/**
+ * rockchip_drm_vblank_disable - Send VBlank disable event.
+ */
+void rockchip_drm_vblank_disable(void)
+{
+	mutex_lock(&vblank_lock);
+	raw_notifier_call_chain(&vblank_chain, VBLANK_DISABLE, NULL);
+	mutex_unlock(&vblank_lock);
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_vblank_disable);
+
+/**
+ * rockchip_drm_vblank_register_notifier - Add notifier to Vblank notifiers.
+ *
+ * Enable notifiers are called when we enable/disable vblank. This can be done
+ * through rockchip_drm_vblank_enable/disable or when there is more than one
+ * sync notifier. Must call rockchip_drm_vblank_lock before calling this.
+ * @nb The notifier to add
+ */
+int rockchip_drm_vblank_register_notifier(struct notifier_block *nb)
+{
+	int ret = 0;
+
+	if (!nb)
+		return -EINVAL;
+
+	ret = raw_notifier_chain_register(&vblank_chain, nb);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_vblank_register_notifier);
+
+/**
+ * rockchip_drm_vblank_unregister_notifier - Remove notifier from Vblank
+ * notifiers.
+ *
+ * Must call rockchip_drm_vblank_lock before calling this.
+ * @nb The notifier to remove.
+ */
+int rockchip_drm_vblank_unregister_notifier(struct notifier_block *nb)
+{
+	int ret = 0;
+
+	if (!nb)
+		return -EINVAL;
+
+	ret = raw_notifier_chain_unregister(&vblank_chain, nb);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_vblank_unregister_notifier);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.h b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h
new file mode 100644
index 0000000..2f28afa
--- /dev/null
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __ROCKCHIP_DRM_NOTIFY_H
+#define __ROCKCHIP_DRM_NOTIFY_H
+
+#include <linux/notifier.h>
+
+enum vblank_enable_op {
+	VBLANK_ENABLE = 0,
+	VBLANK_DISABLE,
+};
+
+void rockchip_drm_vblank_enable(void);
+void rockchip_drm_vblank_disable(void);
+int rockchip_drm_vblank_register_notifier(struct notifier_block *nb);
+int rockchip_drm_vblank_unregister_notifier(struct notifier_block *nb);
+
+#endif /* __ROCKCHIP_DRM_NOTIFY_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index 257501f..fb6ce4b 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -35,6 +35,7 @@
 #include "rockchip_drm_gem.h"
 #include "rockchip_drm_fb.h"
 #include "rockchip_drm_vop.h"
+#include "rockchip_drm_notify.h"
 
 #define __REG_SET_RELAXED(x, off, mask, shift, v, write_mask) \
 		vop_mask_write(x, off, mask, shift, v, write_mask, true)
@@ -851,6 +852,8 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
 
 	spin_unlock_irqrestore(&vop->irq_lock, flags);
 
+	rockchip_drm_vblank_enable();
+
 	return 0;
 }
 
@@ -867,6 +870,8 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
 	VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0);
 
 	spin_unlock_irqrestore(&vop->irq_lock, flags);
+
+	rockchip_drm_vblank_disable();
 }
 
 static void vop_crtc_wait_for_update(struct drm_crtc *crtc)
-- 
1.9.1




From ykk at rock-chips.com  Tue May 31 06:39:50 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Tue, 31 May 2016 21:39:50 +0800
Subject: [RFC PATCH v1 2/2] drm/rockchip: analogix: add eDP PSR function
In-Reply-To: <1464701856-8695-1-git-send-email-ykk@rock-chips.com>
References: <1464701856-8695-1-git-send-email-ykk@rock-chips.com>
Message-ID: <1464701990-10741-1-git-send-email-ykk@rock-chips.com>

The full name of PSR is Panel Self Refresh, panel device could refresh
itself with the hardware framebuffer in panel, this would make a lots
of sense to save the power consumption.

For example, when desktop haven't change the context for a long time,
then we could refresh the data to the hardware framebuffer of panel,
and then let panel enter into PSR mode. After that system could poweroff
the LCDC controller and eDP controller, just let panel refresh the screen
by itself.

Signed-off-by: Yakir Yang <ykk at rock-chips.com>
---
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.c | 69 ++++++++++++++++
 drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |  5 ++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  | 54 +++++++++++++
 drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  | 28 +++++++
 drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 65 ++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_notify.c     | 39 ++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_notify.h     |  4 +
 drivers/gpu/drm/rockchip/rockchip_drm_vop.c        | 91 ++++++++++++++++++++++
 drivers/gpu/drm/rockchip/rockchip_drm_vop.h        |  3 +
 drivers/gpu/drm/rockchip/rockchip_vop_reg.c        |  2 +
 include/drm/bridge/analogix_dp.h                   |  3 +
 11 files changed, 363 insertions(+)

diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
index 5af9ce4..a66ccb6 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.c
@@ -39,6 +39,72 @@ struct bridge_init {
 	struct device_node *node;
 };
 
+int analogix_dp_actice_psr(struct device *dev)
+{
+	struct analogix_dp_device *dp = dev_get_drvdata(dev);
+
+	if (!dp->psr_support)
+		return -EINVAL;
+
+	analogix_dp_send_vsc(dp, EDP_VSC_PSR_STATE_ACTIVE |
+			     EDP_VSC_PSR_CRC_VALUES_VALID);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_actice_psr);
+
+int analogix_dp_inactice_psr(struct device *dev)
+{
+	struct analogix_dp_device *dp = dev_get_drvdata(dev);
+
+	if (!dp->psr_support)
+		return -EINVAL;
+
+	analogix_dp_send_vsc(dp, 0);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(analogix_dp_inactice_psr);
+
+int analogix_dp_enable_psr(struct analogix_dp_device *dp)
+{
+	unsigned char psr_version, psr_caps;
+	unsigned char psr_en;
+
+	/* disable psr function */
+	analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en);
+	psr_en &= ~DP_PSR_ENABLE;
+	analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+	/* check panel psr version */
+	analogix_dp_read_byte_from_dpcd(dp, DP_PSR_SUPPORT, &psr_version);
+	analogix_dp_read_byte_from_dpcd(dp, DP_PSR_CAPS, &psr_caps);
+	dev_info(dp->dev, "Panel PSR version : %x.%x\n", psr_version, psr_caps);
+
+	if (!(psr_version & DP_PSR_IS_SUPPORTED))
+		return -1;
+
+	/* Main-Link transmitter remains active during PSR active states */
+	analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en);
+	psr_en = DP_PSR_MAIN_LINK_ACTIVE | DP_PSR_CRC_VERIFICATION;
+	analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+	/* enable PSR function */
+	analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en);
+	psr_en = DP_PSR_ENABLE | DP_PSR_MAIN_LINK_ACTIVE |
+		 DP_PSR_CRC_VERIFICATION;
+	analogix_dp_write_byte_to_dpcd(dp, DP_PSR_EN_CFG, psr_en);
+
+	/* read sink psr state */
+	analogix_dp_read_byte_from_dpcd(dp, DP_PSR_EN_CFG, &psr_en);
+	dev_info(dp->dev, "DP_PSR_EN_CFG: %x\n", psr_en);
+
+	analogix_dp_enable_psr_crc(dp);
+	dp->psr_support = true;
+
+	return 0;
+}
+
 static void analogix_dp_init_dp(struct analogix_dp_device *dp)
 {
 	analogix_dp_reset(dp);
@@ -921,6 +987,9 @@ static void analogix_dp_commit(struct analogix_dp_device *dp)
 
 	/* Enable video */
 	analogix_dp_start_video(dp);
+
+	/* Enable PSR support */
+	analogix_dp_enable_psr(dp);
 }
 
 int analogix_dp_get_modes(struct drm_connector *connector)
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
index b456380..948e59a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_core.h
@@ -178,6 +178,8 @@ struct analogix_dp_device {
 	bool                    force_hpd;
 	unsigned char           edid[EDID_BLOCK_LENGTH * 2];
 
+	bool			psr_support;
+
 	struct analogix_dp_plat_data *plat_data;
 };
 
@@ -278,4 +280,7 @@ int analogix_dp_is_video_stream_on(struct analogix_dp_device *dp);
 void analogix_dp_config_video_slave_mode(struct analogix_dp_device *dp);
 void analogix_dp_enable_scrambling(struct analogix_dp_device *dp);
 void analogix_dp_disable_scrambling(struct analogix_dp_device *dp);
+void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp);
+void analogix_dp_send_vsc(struct analogix_dp_device *dp, int db1);
+
 #endif /* _ANALOGIX_DP_CORE_H */
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
index 31366bf..8d8c37a 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c
@@ -1322,3 +1322,57 @@ void analogix_dp_disable_scrambling(struct analogix_dp_device *dp)
 	reg |= SCRAMBLING_DISABLE;
 	writel(reg, dp->reg_base + ANALOGIX_DP_TRAINING_PTN_SET);
 }
+
+void analogix_dp_enable_psr_crc(struct analogix_dp_device *dp)
+{
+	writel(PSR_VID_CRC_FLUSH | PSR_VID_CRC_ENABLE,
+	       dp->reg_base + ANALOGIX_DP_CRC_CON);
+
+	usleep_range(10, 20);
+
+	writel(PSR_VID_CRC_ENABLE, dp->reg_base + ANALOGIX_DP_CRC_CON);
+}
+
+void analogix_dp_send_vsc(struct analogix_dp_device *dp, int db1)
+{
+	unsigned int val;
+
+	/* don't send info frame */
+	val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+	val &= ~IF_EN;
+	writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+	/* configure single frame update mode */
+	writel(0x3, dp->reg_base + ANALOGIX_DP_PSR_FRAME_UPDATE_CTRL);
+
+	/* configure VSC HB0 ~ HB3 */
+	writel(0x00, dp->reg_base + ANALOGIX_DP_SPD_HB0);
+	writel(0x07, dp->reg_base + ANALOGIX_DP_SPD_HB1);
+	writel(0x02, dp->reg_base + ANALOGIX_DP_SPD_HB2);
+	writel(0x08, dp->reg_base + ANALOGIX_DP_SPD_HB3);
+
+	/* configure VSC HB0 ~ HB3 */
+	writel(0x00, dp->reg_base + ANALOGIX_DP_SPD_PB0);
+	writel(0x16, dp->reg_base + ANALOGIX_DP_SPD_PB1);
+	writel(0xCE, dp->reg_base + ANALOGIX_DP_SPD_PB2);
+	writel(0x5D, dp->reg_base + ANALOGIX_DP_SPD_PB3);
+
+	/* configure DB0 / DB1 values */
+	writel(0x00, dp->reg_base + ANALOGIX_DP_VSC_SHADOW_DB0);
+	writel(db1, dp->reg_base + ANALOGIX_DP_VSC_SHADOW_DB1);
+
+	/* set reuse spd inforframe */
+	val = readl(dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3);
+	val |= REUSE_SPD_EN;
+	writel(val, dp->reg_base + ANALOGIX_DP_VIDEO_CTL_3);
+
+	/* mark info frame update */
+	val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+	val = (val | IF_UP) & ~IF_EN;
+	writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+
+	/* send info frame */
+	val = readl(dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+	val |= IF_EN;
+	writel(val, dp->reg_base + ANALOGIX_DP_PKT_SEND_CTL);
+}
diff --git a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
index cdcc6c5..a2698e4 100644
--- a/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
+++ b/drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h
@@ -22,6 +22,8 @@
 #define ANALOGIX_DP_VIDEO_CTL_8			0x3C
 #define ANALOGIX_DP_VIDEO_CTL_10		0x44
 
+#define ANALOGIX_DP_SPDIF_AUDIO_CTL_0		0xD8
+
 #define ANALOGIX_DP_PLL_REG_1			0xfc
 #define ANALOGIX_DP_PLL_REG_2			0x9e4
 #define ANALOGIX_DP_PLL_REG_3			0x9e8
@@ -30,6 +32,21 @@
 
 #define ANALOGIX_DP_PD				0x12c
 
+#define ANALOGIX_DP_IF_TYPE			0x244
+#define ANALOGIX_DP_IF_PKT_DB1			0x254
+#define ANALOGIX_DP_IF_PKT_DB2			0x258
+#define ANALOGIX_DP_SPD_HB0			0x2F8
+#define ANALOGIX_DP_SPD_HB1			0x2FC
+#define ANALOGIX_DP_SPD_HB2			0x300
+#define ANALOGIX_DP_SPD_HB3			0x304
+#define ANALOGIX_DP_SPD_PB0			0x308
+#define ANALOGIX_DP_SPD_PB1			0x30C
+#define ANALOGIX_DP_SPD_PB2			0x310
+#define ANALOGIX_DP_SPD_PB3			0x314
+#define ANALOGIX_DP_PSR_FRAME_UPDATE_CTRL	0x318
+#define ANALOGIX_DP_VSC_SHADOW_DB0		0x31C
+#define ANALOGIX_DP_VSC_SHADOW_DB1		0x320
+
 #define ANALOGIX_DP_LANE_MAP			0x35C
 
 #define ANALOGIX_DP_ANALOG_CTL_1		0x370
@@ -103,6 +120,8 @@
 
 #define ANALOGIX_DP_SOC_GENERAL_CTL		0x800
 
+#define ANALOGIX_DP_CRC_CON			0x890
+
 /* ANALOGIX_DP_TX_SW_RESET */
 #define RESET_DP_TX				(0x1 << 0)
 
@@ -151,6 +170,7 @@
 #define VID_CHK_UPDATE_TYPE_SHIFT		(4)
 #define VID_CHK_UPDATE_TYPE_1			(0x1 << 4)
 #define VID_CHK_UPDATE_TYPE_0			(0x0 << 4)
+#define REUSE_SPD_EN				(0x1 << 3)
 
 /* ANALOGIX_DP_VIDEO_CTL_8 */
 #define VID_HRES_TH(x)				(((x) & 0xf) << 4)
@@ -376,4 +396,12 @@
 #define VIDEO_MODE_SLAVE_MODE			(0x1 << 0)
 #define VIDEO_MODE_MASTER_MODE			(0x0 << 0)
 
+/* ANALOGIX_DP_PKT_SEND_CTL */
+#define IF_UP					(0x1 << 4)
+#define IF_EN					(0x1 << 0)
+
+/* ANALOGIX_DP_CRC_CON */
+#define PSR_VID_CRC_FLUSH			(0x1 << 2)
+#define PSR_VID_CRC_ENABLE			(0x1 << 0)
+
 #endif /* _ANALOGIX_DP_REG_H */
diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
index eb1b8ac..44a7a27 100644
--- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
+++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
@@ -33,6 +33,7 @@
 
 #include "rockchip_drm_drv.h"
 #include "rockchip_drm_vop.h"
+#include "rockchip_drm_notify.h"
 
 #define to_dp(nm)	container_of(nm, struct rockchip_dp_device, nm)
 
@@ -54,6 +55,12 @@ struct rockchip_dp_device {
 	struct regmap            *grf;
 	struct reset_control     *rst;
 
+	struct workqueue_struct	 *dp_workq;
+	struct work_struct	 psr_work;
+	struct notifier_block    psr_nb;
+	unsigned int		 psr_state;
+	struct mutex		 psr_state_mutex;
+
 	const struct rockchip_dp_chip_data *data;
 
 	struct analogix_dp_plat_data plat_data;
@@ -97,6 +104,50 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
 	return 0;
 }
 
+static int psr_notify(struct notifier_block *psr_nb, unsigned long action,
+		      void *data)
+{
+	struct rockchip_dp_device *dp = to_dp(psr_nb);
+
+	switch (action) {
+	case VBLANK_ENABLE:
+		mutex_lock(&dp->psr_state_mutex);
+		dp->psr_state = 0;
+		mutex_unlock(&dp->psr_state_mutex);
+		break;
+
+	case VBLANK_DISABLE:
+		mutex_lock(&dp->psr_state_mutex);
+		dp->psr_state = EDP_VSC_PSR_STATE_ACTIVE;
+		mutex_unlock(&dp->psr_state_mutex);
+		break;
+
+	default:
+		return 0;
+	}
+
+	queue_work(dp->dp_workq, &dp->psr_work);
+
+	return 0;
+}
+
+static void dp_psr_work(struct work_struct *psr_work)
+{
+	struct rockchip_dp_device *dp = to_dp(psr_work);
+	int psr_state = dp->psr_state;
+	int ret;
+
+	if (psr_state == EDP_VSC_PSR_STATE_ACTIVE) {
+		ret = rockchip_psr_ready_wait();
+		if (ret == 0)
+			analogix_dp_actice_psr(dp->dev);
+	} else {
+		ret = rockchip_psr_ready_wait();
+		if (ret == 0)
+			analogix_dp_inactice_psr(dp->dev);
+	}
+}
+
 static enum drm_mode_status
 rockchip_dp_mode_valid(struct analogix_dp_plat_data *plat_data,
 		       struct drm_connector *connector,
@@ -131,6 +182,7 @@ static void rockchip_dp_drm_encoder_mode_set(struct drm_encoder *encoder,
 	/* do nothing */
 }
 
+
 static void rockchip_dp_drm_encoder_enable(struct drm_encoder *encoder)
 {
 	struct rockchip_dp_device *dp = to_dp(encoder);
@@ -322,6 +374,19 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
 	dp->plat_data.power_off = rockchip_dp_powerdown;
 	dp->plat_data.mode_valid = rockchip_dp_mode_valid;
 
+	dp->psr_nb.notifier_call = psr_notify;
+	rockchip_drm_vblank_register_notifier(&dp->psr_nb);
+
+	dp->dp_workq = create_singlethread_workqueue("dp");
+	if (!dp->dp_workq) {
+		dev_err(dp->dev, "failed to create workqueue\n");
+		return PTR_ERR(dp->dp_workq);
+	}
+
+	dp->psr_state = 0;
+	mutex_init(&dp->psr_state_mutex);
+	INIT_WORK(&dp->psr_work, dp_psr_work);
+
 	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
 }
 
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.c b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c
index 84111d9..652f03f 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_notify.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c
@@ -1,7 +1,9 @@
 #include "rockchip_drm_notify.h"
 
 static RAW_NOTIFIER_HEAD(vblank_chain);
+static RAW_NOTIFIER_HEAD(psr_ready_chain);
 static DEFINE_MUTEX(vblank_lock);
+static DEFINE_MUTEX(psr_ready_lock);
 
 /**
  * rockchip_drm_vblank_enable - Send Vblank enable event. Will only enable send
@@ -64,3 +66,40 @@ int rockchip_drm_vblank_unregister_notifier(struct notifier_block *nb)
 	return ret;
 }
 EXPORT_SYMBOL_GPL(rockchip_drm_vblank_unregister_notifier);
+
+
+int rockchip_drm_psr_ready_register_notifier(struct notifier_block *nb)
+{
+	int ret = 0;
+
+	if (!nb)
+		return -EINVAL;
+
+	ret = raw_notifier_chain_register(&psr_ready_chain, nb);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_psr_ready_register_notifier);
+
+int rockchip_drm_psr_ready_unregister_notifier(struct notifier_block *nb)
+{
+	int ret = 0;
+
+	if (!nb)
+		return -EINVAL;
+
+	ret = raw_notifier_chain_unregister(&psr_ready_chain, nb);
+	return ret;
+}
+EXPORT_SYMBOL_GPL(rockchip_drm_psr_ready_unregister_notifier);
+
+int rockchip_psr_ready_wait(void)
+{
+	int ret;
+
+	ret = raw_notifier_call_chain(&psr_ready_chain, 0, 0);
+	if (ret == NOTIFY_BAD)
+		return -ETIMEDOUT;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(rockchip_psr_ready_wait);
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.h b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h
index 2f28afa..34614fc 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_notify.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h
@@ -26,4 +26,8 @@ void rockchip_drm_vblank_disable(void);
 int rockchip_drm_vblank_register_notifier(struct notifier_block *nb);
 int rockchip_drm_vblank_unregister_notifier(struct notifier_block *nb);
 
+int rockchip_psr_ready_wait(void);
+int rockchip_drm_psr_ready_register_notifier(struct notifier_block *nb);
+int rockchip_drm_psr_ready_unregister_notifier(struct notifier_block *nb);
+
 #endif /* __ROCKCHIP_DRM_NOTIFY_H */
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
index fb6ce4b..53d1809 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
@@ -118,6 +118,9 @@ struct vop {
 	struct completion wait_update_complete;
 	struct drm_pending_vblank_event *event;
 
+	struct notifier_block psr_prepare_nb;
+	struct completion line_flag_completion;
+
 	const struct vop_data *data;
 
 	uint32_t *regsbak;
@@ -428,6 +431,59 @@ static void vop_dsp_hold_valid_irq_disable(struct vop *vop)
 	spin_unlock_irqrestore(&vop->irq_lock, flags);
 }
 
+/*
+ * (1) each frame starts at the start of the Vsync pulse which is signaled by
+ *     the "FRAME_SYNC" interrupt.
+ * (2) the active data region of each frame ends at dsp_vact_end
+ * (3) we should program this same number (dsp_vact_end) into dsp_line_frag_num,
+ *      to get "LINE_FLAG" interrupt at the end of the active on screen data.
+ *
+ * VOP_INTR_CTRL0.dsp_line_frag_num = VOP_DSP_VACT_ST_END.dsp_vact_end
+ * Interrupts
+ * LINE_FLAG -------------------------------+
+ * FRAME_SYNC ----+                         |
+ *                |                         |
+ *                v                         v
+ *                | Vsync | Vbp |  Vactive  | Vfp |
+ *                        ^     ^           ^     ^
+ *                        |     |           |     |
+ *                        |     |           |     |
+ * dsp_vs_end ------------+     |           |     |   VOP_DSP_VTOTAL_VS_END
+ * dsp_vact_start --------------+           |     |   VOP_DSP_VACT_ST_END
+ * dsp_vact_end ----------------------------+     |   VOP_DSP_VACT_ST_END
+ * dsp_total -------------------------------------+   VOP_DSP_VTOTAL_VS_END
+ */
+
+static void vop_line_flag_irq_enable(struct vop *vop, int line_num)
+{
+	unsigned long flags;
+
+	if (WARN_ON(!vop->is_enabled))
+		return;
+
+	spin_lock_irqsave(&vop->irq_lock, flags);
+
+	VOP_CTRL_SET(vop, line_flag_num_0, line_num);
+	VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 1);
+	vop_cfg_done(vop);
+
+	spin_unlock_irqrestore(&vop->irq_lock, flags);
+}
+
+static void vop_line_flag_irq_disable(struct vop *vop)
+{
+	unsigned long flags;
+
+	if (WARN_ON(!vop->is_enabled))
+		return;
+
+	spin_lock_irqsave(&vop->irq_lock, flags);
+
+	VOP_INTR_SET_TYPE(vop, enable, LINE_FLAG_INTR, 0);
+
+	spin_unlock_irqrestore(&vop->irq_lock, flags);
+}
+
 static void vop_enable(struct drm_crtc *crtc)
 {
 	struct vop *vop = to_vop(crtc);
@@ -1128,6 +1184,30 @@ static void vop_handle_vblank(struct vop *vop)
 		complete(&vop->wait_update_complete);
 }
 
+static int psr_prepare_notify(struct notifier_block *psr_prepare_nb,
+			      unsigned long action, void *data)
+{
+	struct vop *vop = container_of(psr_prepare_nb, struct vop,
+				       psr_prepare_nb);
+	struct drm_display_mode *mode = &vop->crtc.mode;
+	int vact_end = mode->vtotal - mode->vsync_start + mode->vdisplay;
+	unsigned long jiffies_left;
+
+	reinit_completion(&vop->line_flag_completion);
+	vop_line_flag_irq_enable(vop, vact_end);
+
+	jiffies_left = wait_for_completion_timeout(&vop->line_flag_completion,
+						   msecs_to_jiffies(200));
+	vop_line_flag_irq_disable(vop);
+
+	if (jiffies_left == 0) {
+		dev_err(vop->dev, "Timeout waiting for IRQ\n");
+		return NOTIFY_BAD;
+	}
+
+	return NOTIFY_STOP;
+}
+
 static irqreturn_t vop_isr(int irq, void *data)
 {
 	struct vop *vop = data;
@@ -1159,6 +1239,13 @@ static irqreturn_t vop_isr(int irq, void *data)
 		ret = IRQ_HANDLED;
 	}
 
+	if (active_irqs & LINE_FLAG_INTR) {
+		if (!completion_done(&vop->line_flag_completion))
+			complete(&vop->line_flag_completion);
+		active_irqs &= ~LINE_FLAG_INTR;
+		ret = IRQ_HANDLED;
+	}
+
 	if (active_irqs & FS_INTR) {
 		drm_crtc_handle_vblank(crtc);
 		vop_handle_vblank(vop);
@@ -1255,8 +1342,12 @@ static int vop_create_crtc(struct vop *vop)
 		goto err_cleanup_crtc;
 	}
 
+	vop->psr_prepare_nb.notifier_call = psr_prepare_notify;
+	rockchip_drm_psr_ready_register_notifier(&vop->psr_prepare_nb);
+
 	init_completion(&vop->dsp_hold_completion);
 	init_completion(&vop->wait_update_complete);
+	init_completion(&vop->line_flag_completion);
 	crtc->port = port;
 	rockchip_register_crtc_funcs(crtc, &private_crtc_funcs);
 
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
index ff4f52e..34fcd03 100644
--- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
+++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.h
@@ -61,6 +61,9 @@ struct vop_ctrl {
 	struct vop_reg hpost_st_end;
 	struct vop_reg vpost_st_end;
 
+	struct vop_reg line_flag_num_0;
+	struct vop_reg line_flag_num_1;
+
 	struct vop_reg cfg_done;
 };
 
diff --git a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
index 6f42e56..bf78892 100644
--- a/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
+++ b/drivers/gpu/drm/rockchip/rockchip_vop_reg.c
@@ -299,6 +299,8 @@ static const struct vop_ctrl rk3399_ctrl_data = {
 	.vact_st_end = VOP_REG(RK3399_DSP_VACT_ST_END, 0x1fff1fff, 0),
 	.hpost_st_end = VOP_REG(RK3399_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
 	.vpost_st_end = VOP_REG(RK3399_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
+	.line_flag_num_0 = VOP_REG(RK3399_LINE_FLAG, 0xffff, 0),
+	.line_flag_num_1 = VOP_REG(RK3399_LINE_FLAG, 0xffff, 16),
 	.cfg_done = VOP_REG_MASK(RK3399_REG_CFG_DONE, 0x1, 0),
 };
 
diff --git a/include/drm/bridge/analogix_dp.h b/include/drm/bridge/analogix_dp.h
index 9ef89de..dd38527 100644
--- a/include/drm/bridge/analogix_dp.h
+++ b/include/drm/bridge/analogix_dp.h
@@ -41,6 +41,9 @@ struct analogix_dp_plat_data {
 					   struct drm_display_mode *);
 };
 
+int analogix_dp_actice_psr(struct device *dev);
+int analogix_dp_inactice_psr(struct device *dev);
+
 int analogix_dp_resume(struct device *dev);
 int analogix_dp_suspend(struct device *dev);
 
-- 
1.9.1




From huangtao at rock-chips.com  Tue May 31 06:45:51 2016
From: huangtao at rock-chips.com (Huang, Tao)
Date: Tue, 31 May 2016 21:45:51 +0800
Subject: [PATCH 3/5] clocksource: rockchip: add dynamic irq flag to the
 timer
In-Reply-To: <574CC9DE.1050501@linaro.org>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-4-git-send-email-wxt@rock-chips.com>
 <574CC9DE.1050501@linaro.org>
Message-ID: <574D958F.9010707@rock-chips.com>

Hi Daniel:
On 2016?05?31? 07:16, Daniel Lezcano wrote:
> On 05/25/2016 11:50 AM, Caesar Wang wrote:
>> From: Huang Tao <huangtao at rock-chips.com>
>>
>> The rockchip timer is broadcast timer. Add CLOCK_EVT_FEAT_DYNIRQ
>> flag and set cpumask to all cpu to save power by avoid unnecessary
>> wakeups and IPIs.
>>
>> Signed-off-by: Huang Tao <huangtao at rock-chips.com>
>> Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
>> Cc: Thomas Gleixner <tglx at linutronix.de>
>> Cc: Heiko Stuebner <heiko at sntech.de>
>> Tested-by: Jianqun Xu <jay.xu at rock-chips.com>
>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>> ---
>>
>>   drivers/clocksource/rockchip_timer.c | 5 +++--
>>   1 file changed, 3 insertions(+), 2 deletions(-)
>>
>> diff --git a/drivers/clocksource/rockchip_timer.c b/drivers/clocksource/rockchip_timer.c
>> index b93fed6..f3dfb1a 100644
>> --- a/drivers/clocksource/rockchip_timer.c
>> +++ b/drivers/clocksource/rockchip_timer.c
>> @@ -150,12 +150,13 @@ static void __init rk_timer_init(struct device_node *np)
>>   	}
>>
>>   	ce->name = TIMER_NAME;
>> -	ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT;
>> +	ce->features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT |
>> +		       CLOCK_EVT_FEAT_DYNIRQ;
>>   	ce->set_next_event = rk_timer_set_next_event;
>>   	ce->set_state_shutdown = rk_timer_shutdown;
>>   	ce->set_state_periodic = rk_timer_set_periodic;
>>   	ce->irq = irq;
>> -	ce->cpumask = cpumask_of(0);
>> +	ce->cpumask = cpu_all_mask;
> 
> s/cpu_all_mask/cpu_possible_mask/

Okay for me.
It seems drivers in drivers/clocksource are very confusing about use
cpu_all_mask or cpu_possible_mask. For example arm_arch_timer.c use
cpu_all_mask, while mtk_timer.c use cpu_possible_mask. I think all just
work.

Thanks,
Huang, Tao



From huangtao at rock-chips.com  Tue May 31 06:46:23 2016
From: huangtao at rock-chips.com (Huang, Tao)
Date: Tue, 31 May 2016 21:46:23 +0800
Subject: [PATCH 4/5] clocksource: rockchip: add support for rk3399 SoC
In-Reply-To: <574CCCB4.1030001@linaro.org>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-5-git-send-email-wxt@rock-chips.com>
 <574CCCB4.1030001@linaro.org>
Message-ID: <574D95AF.2020905@rock-chips.com>

Hi Daniel:
On 2016?05?31? 07:28, Daniel Lezcano wrote:
> On 05/25/2016 11:50 AM, Caesar Wang wrote:
>> From: Huang Tao <huangtao at rock-chips.com>
>>
>> The CONTROL register offset is different from old SoCs.
>> For Linux driver, there are not functional changes at all.
>> Let's call it v2.
>>
>> Signed-off-by: Huang Tao <huangtao at rock-chips.com>
>> Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
>> Cc: Thomas Gleixner <tglx at linutronix.de>
>> Cc: Heiko Stuebner <heiko at sntech.de>
>> Tested-by: Jianqun Xu <jay.xu at rock-chips.com>
>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>> ---
> 
> That's hackish.
Yes:( I blamed our IC guy.
> 
> Please consider something like:
> 
> diff --git a/drivers/clocksource/rockchip_timer.c 
> b/drivers/clocksource/rockchip_timer.c
> index b991b28..b6ba6f9 100644
> --- a/drivers/clocksource/rockchip_timer.c
> +++ b/drivers/clocksource/rockchip_timer.c
> @@ -19,7 +19,8 @@
> 
>   #define TIMER_LOAD_COUNT0	0x00
>   #define TIMER_LOAD_COUNT1	0x04
> -#define TIMER_CONTROL_REG	0x10
> +#define TIMER_CONTROL_REG3288	0x10
> +#define TIMER_CONTROL_REG3399	0x1C
>   #define TIMER_INT_STATUS	0x18
> 
>   #define TIMER_DISABLE		0x0
> @@ -31,6 +32,7 @@
>   struct bc_timer {
>   	struct clock_event_device ce;
>   	void __iomem *base;
> +	void __iomem *ctrl;
>   	u32 freq;
>   };
> 
> @@ -46,15 +48,20 @@ static inline void __iomem *rk_base(struct 
> clock_event_device *ce)
>   	return rk_timer(ce)->base;
>   }
> 
> +static inline void __iomem *rk_ctrl(struct clock_event_device *ce)
> +{
> +        return rk_timer(ce)->ctrl;
> +}
> +
>   static inline void rk_timer_disable(struct clock_event_device *ce)
>   {
> -	writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
> +	writel_relaxed(TIMER_DISABLE, rk_ctrl(ce));
>   }
> 
>   static inline void rk_timer_enable(struct clock_event_device *ce, u32 
> flags)
>   {
>   	writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
> -		       rk_base(ce) + TIMER_CONTROL_REG);
> +		       rk_ctrl(ce));
>   }
> 
>   static void rk_timer_update_counter(unsigned long cycles,
> @@ -179,4 +186,18 @@ out_unmap:
>   	iounmap(bc_timer.base);
>   }
> 
> -CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
> +static void __init rk3288_timer_init(struct device_node *np)
> +{
> +	bc_timer.ctrl = TIMER_CONTROL_REG3288;
> +	rk_timer_init(np);
> +}
> +
> +static void __init rk3399_timer_init(struct device_node *np)
> +{
> +        bc_timer.ctrl = TIMER_CONTROL_REG3399;
> +	rk_timer_init(np);
> +}
> +
> +
> +CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", 
> rk3288_timer_init);
> +CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3399-timer", 
> rk3399_timer_init);
> 
> 

I think you mean this patch otherwise compile will fail:
@@ -19,7 +19,8 @@

 #define TIMER_LOAD_COUNT0	0x00
 #define TIMER_LOAD_COUNT1	0x04
-#define TIMER_CONTROL_REG	0x10
+#define TIMER_CONTROL_REG3288	0x10
+#define TIMER_CONTROL_REG3399	0x1C
 #define TIMER_INT_STATUS	0x18

 #define TIMER_DISABLE		0x0
@@ -31,6 +32,7 @@
 struct bc_timer {
 	struct clock_event_device ce;
 	void __iomem *base;
+	u32 ctrl;
 	u32 freq;
 };

@@ -46,15 +48,20 @@ static inline void __iomem *rk_base(struct
clock_event_device *ce)
 	return rk_timer(ce)->base;
 }

+static inline void __iomem *rk_ctrl(struct clock_event_device *ce)
+{
+	return rk_timer(ce)->base + rk_timer(ce)->ctrl;
+}
+
 static inline void rk_timer_disable(struct clock_event_device *ce)
 {
-	writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
+	writel_relaxed(TIMER_DISABLE, rk_ctrl(ce));
 }

 static inline void rk_timer_enable(struct clock_event_device *ce, u32
flags)
 {
 	writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
-		       rk_base(ce) + TIMER_CONTROL_REG);
+		       rk_ctrl(ce));
 }

 static void rk_timer_update_counter(unsigned long cycles,
@@ -179,4 +186,19 @@ out_unmap:
 	iounmap(bc_timer.base);
 }

-CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
+static void __init rk3288_timer_init(struct device_node *np)
+{
+	bc_timer.ctrl = TIMER_CONTROL_REG3288;
+	rk_timer_init(np);
+}
+
+static void __init rk3399_timer_init(struct device_node *np)
+{
+	bc_timer.ctrl = TIMER_CONTROL_REG3399;
+	rk_timer_init(np);
+}
+
+CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer",
+		       rk3288_timer_init);
+CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer",
+		       rk3399_timer_init);

This patch will give us a little lager text size. If we do disassemble,
we can see additional LDR is called. I can accept this performance drop.
So we will send new patches.
BTW, the patch "clocksource: rockchip: remove unnecessary clear irq
before request_irq" can drop if we use this patch.

Thanks,
Huang, Tao



From daniel.lezcano at linaro.org  Tue May 31 07:06:30 2016
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Tue, 31 May 2016 16:06:30 +0200
Subject: [PATCH 4/5] clocksource: rockchip: add support for rk3399 SoC
In-Reply-To: <574D95AF.2020905@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-5-git-send-email-wxt@rock-chips.com>
 <574CCCB4.1030001@linaro.org> <574D95AF.2020905@rock-chips.com>
Message-ID: <574D9A66.4090209@linaro.org>

On 05/31/2016 03:46 PM, Huang, Tao wrote:
> Hi Daniel:
> On 2016?05?31? 07:28, Daniel Lezcano wrote:
>> On 05/25/2016 11:50 AM, Caesar Wang wrote:
>>> From: Huang Tao <huangtao at rock-chips.com>
>>>
>>> The CONTROL register offset is different from old SoCs.
>>> For Linux driver, there are not functional changes at all.
>>> Let's call it v2.
>>>
>>> Signed-off-by: Huang Tao <huangtao at rock-chips.com>
>>> Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
>>> Cc: Thomas Gleixner <tglx at linutronix.de>
>>> Cc: Heiko Stuebner <heiko at sntech.de>
>>> Tested-by: Jianqun Xu <jay.xu at rock-chips.com>
>>> Signed-off-by: Caesar Wang <wxt at rock-chips.com>
>>> ---
>>
>> That's hackish.
> Yes:( I blamed our IC guy.
>>
>> Please consider something like:
>>
>> diff --git a/drivers/clocksource/rockchip_timer.c
>> b/drivers/clocksource/rockchip_timer.c
>> index b991b28..b6ba6f9 100644
>> --- a/drivers/clocksource/rockchip_timer.c
>> +++ b/drivers/clocksource/rockchip_timer.c
>> @@ -19,7 +19,8 @@
>>
>>    #define TIMER_LOAD_COUNT0	0x00
>>    #define TIMER_LOAD_COUNT1	0x04
>> -#define TIMER_CONTROL_REG	0x10
>> +#define TIMER_CONTROL_REG3288	0x10
>> +#define TIMER_CONTROL_REG3399	0x1C
>>    #define TIMER_INT_STATUS	0x18
>>
>>    #define TIMER_DISABLE		0x0
>> @@ -31,6 +32,7 @@
>>    struct bc_timer {
>>    	struct clock_event_device ce;
>>    	void __iomem *base;
>> +	void __iomem *ctrl;
>>    	u32 freq;
>>    };
>>
>> @@ -46,15 +48,20 @@ static inline void __iomem *rk_base(struct
>> clock_event_device *ce)
>>    	return rk_timer(ce)->base;
>>    }
>>
>> +static inline void __iomem *rk_ctrl(struct clock_event_device *ce)
>> +{
>> +        return rk_timer(ce)->ctrl;
>> +}
>> +
>>    static inline void rk_timer_disable(struct clock_event_device *ce)
>>    {
>> -	writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
>> +	writel_relaxed(TIMER_DISABLE, rk_ctrl(ce));
>>    }
>>
>>    static inline void rk_timer_enable(struct clock_event_device *ce, u32
>> flags)
>>    {
>>    	writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
>> -		       rk_base(ce) + TIMER_CONTROL_REG);
>> +		       rk_ctrl(ce));
>>    }
>>
>>    static void rk_timer_update_counter(unsigned long cycles,
>> @@ -179,4 +186,18 @@ out_unmap:
>>    	iounmap(bc_timer.base);
>>    }
>>
>> -CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
>> +static void __init rk3288_timer_init(struct device_node *np)
>> +{
>> +	bc_timer.ctrl = TIMER_CONTROL_REG3288;
>> +	rk_timer_init(np);
>> +}
>> +
>> +static void __init rk3399_timer_init(struct device_node *np)
>> +{
>> +        bc_timer.ctrl = TIMER_CONTROL_REG3399;
>> +	rk_timer_init(np);
>> +}
>> +
>> +
>> +CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer",
>> rk3288_timer_init);
>> +CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3399-timer",
>> rk3399_timer_init);
>>
>>
>
> I think you mean this patch otherwise compile will fail:
> @@ -19,7 +19,8 @@
>
>   #define TIMER_LOAD_COUNT0	0x00
>   #define TIMER_LOAD_COUNT1	0x04
> -#define TIMER_CONTROL_REG	0x10
> +#define TIMER_CONTROL_REG3288	0x10
> +#define TIMER_CONTROL_REG3399	0x1C
>   #define TIMER_INT_STATUS	0x18
>
>   #define TIMER_DISABLE		0x0
> @@ -31,6 +32,7 @@
>   struct bc_timer {
>   	struct clock_event_device ce;
>   	void __iomem *base;
> +	u32 ctrl;
>   	u32 freq;
>   };
>
> @@ -46,15 +48,20 @@ static inline void __iomem *rk_base(struct
> clock_event_device *ce)
>   	return rk_timer(ce)->base;
>   }
>
> +static inline void __iomem *rk_ctrl(struct clock_event_device *ce)
> +{
> +	return rk_timer(ce)->base + rk_timer(ce)->ctrl;

You can do a small optimization by pre-computing 'ctrl' at init time, so 
no need to do this addition each time.

> +}
> +
>   static inline void rk_timer_disable(struct clock_event_device *ce)
>   {
> -	writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
> +	writel_relaxed(TIMER_DISABLE, rk_ctrl(ce));
>   }
>
>   static inline void rk_timer_enable(struct clock_event_device *ce, u32
> flags)
>   {
>   	writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
> -		       rk_base(ce) + TIMER_CONTROL_REG);
> +		       rk_ctrl(ce));
>   }
>
>   static void rk_timer_update_counter(unsigned long cycles,
> @@ -179,4 +186,19 @@ out_unmap:
>   	iounmap(bc_timer.base);
>   }
>
> -CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
> +static void __init rk3288_timer_init(struct device_node *np)
> +{
> +	bc_timer.ctrl = TIMER_CONTROL_REG3288;
> +	rk_timer_init(np);

	rk_timer_init(np);
	bc_timer.ctrl = bc_timer.base + TIMER_CONTROL_REG3288;

> +}
> +
> +static void __init rk3399_timer_init(struct device_node *np)
> +{
> +	bc_timer.ctrl = TIMER_CONTROL_REG3399;
> +	rk_timer_init(np);

	rk_timer_init(np);
	bc_timer.ctrl = bc_timer.base + TIMER_CONTROL_REG3399;

> +}
> +
> +CLOCKSOURCE_OF_DECLARE(rk3288_timer, "rockchip,rk3288-timer",
> +		       rk3288_timer_init);
> +CLOCKSOURCE_OF_DECLARE(rk3399_timer, "rockchip,rk3399-timer",
> +		       rk3399_timer_init);
>
> This patch will give us a little lager text size. If we do disassemble,
> we can see additional LDR is called. I can accept this performance drop.
> So we will send new patches.
> BTW, the patch "clocksource: rockchip: remove unnecessary clear irq
> before request_irq" can drop if we use this patch.


-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog



From daniel at ffwll.ch  Tue May 31 07:36:15 2016
From: daniel at ffwll.ch (Daniel Vetter)
Date: Tue, 31 May 2016 16:36:15 +0200
Subject: [RFC PATCH v1 1/2] drm/rockchip: add a notify event about vblank
 enable/disable
In-Reply-To: <1464701959-9428-1-git-send-email-ykk@rock-chips.com>
References: <1464701856-8695-1-git-send-email-ykk@rock-chips.com>
 <1464701959-9428-1-git-send-email-ykk@rock-chips.com>
Message-ID: <20160531143615.GJ7231@phenom.ffwll.local>

On Tue, May 31, 2016 at 09:39:19PM +0800, Yakir Yang wrote:
> EDP PSR function is interesting in vblank enable or disable event,
> so it would be great introduce a way to notify encoder about this
> event.
> 
> Signed-off-by: Yakir Yang <ykk at rock-chips.com>

notifiers considered evil, especially if you add a global notifier for
something that's very specific to a given crtc.

I think the better fix would be add a suitable hook to drm_bridge to allow
encoders to go into self refresh, and to wake them up from self-refresh
again.
-Daniel

> ---
>  drivers/gpu/drm/rockchip/Makefile              |  2 +-
>  drivers/gpu/drm/rockchip/rockchip_drm_notify.c | 66 ++++++++++++++++++++++++++
>  drivers/gpu/drm/rockchip/rockchip_drm_notify.h | 29 +++++++++++
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.c    |  5 ++
>  4 files changed, 101 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.c
>  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.h
> 
> diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
> index 05d0713..49fee8c 100644
> --- a/drivers/gpu/drm/rockchip/Makefile
> +++ b/drivers/gpu/drm/rockchip/Makefile
> @@ -3,7 +3,7 @@
>  # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
>  
>  rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
> -		rockchip_drm_gem.o rockchip_drm_vop.o
> +		rockchip_drm_gem.o rockchip_drm_vop.o rockchip_drm_notify.o
>  rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
>  
>  obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.c b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c
> new file mode 100644
> index 0000000..84111d9
> --- /dev/null
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c
> @@ -0,0 +1,66 @@
> +#include "rockchip_drm_notify.h"
> +
> +static RAW_NOTIFIER_HEAD(vblank_chain);
> +static DEFINE_MUTEX(vblank_lock);
> +
> +/**
> + * rockchip_drm_vblank_enable - Send Vblank enable event. Will only enable send
> + * Vblank if there are 1 or fewer notifiers.
> + */
> +void rockchip_drm_vblank_enable(void)
> +{
> +	mutex_lock(&vblank_lock);
> +	raw_notifier_call_chain(&vblank_chain, VBLANK_ENABLE, NULL);
> +	mutex_unlock(&vblank_lock);
> +}
> +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_enable);
> +
> +/**
> + * rockchip_drm_vblank_disable - Send VBlank disable event.
> + */
> +void rockchip_drm_vblank_disable(void)
> +{
> +	mutex_lock(&vblank_lock);
> +	raw_notifier_call_chain(&vblank_chain, VBLANK_DISABLE, NULL);
> +	mutex_unlock(&vblank_lock);
> +}
> +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_disable);
> +
> +/**
> + * rockchip_drm_vblank_register_notifier - Add notifier to Vblank notifiers.
> + *
> + * Enable notifiers are called when we enable/disable vblank. This can be done
> + * through rockchip_drm_vblank_enable/disable or when there is more than one
> + * sync notifier. Must call rockchip_drm_vblank_lock before calling this.
> + * @nb The notifier to add
> + */
> +int rockchip_drm_vblank_register_notifier(struct notifier_block *nb)
> +{
> +	int ret = 0;
> +
> +	if (!nb)
> +		return -EINVAL;
> +
> +	ret = raw_notifier_chain_register(&vblank_chain, nb);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_register_notifier);
> +
> +/**
> + * rockchip_drm_vblank_unregister_notifier - Remove notifier from Vblank
> + * notifiers.
> + *
> + * Must call rockchip_drm_vblank_lock before calling this.
> + * @nb The notifier to remove.
> + */
> +int rockchip_drm_vblank_unregister_notifier(struct notifier_block *nb)
> +{
> +	int ret = 0;
> +
> +	if (!nb)
> +		return -EINVAL;
> +
> +	ret = raw_notifier_chain_unregister(&vblank_chain, nb);
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_unregister_notifier);
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.h b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h
> new file mode 100644
> index 0000000..2f28afa
> --- /dev/null
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h
> @@ -0,0 +1,29 @@
> +/*
> + * Copyright (C) 2014 Google, Inc.
> + *
> + * This software is licensed under the terms of the GNU General Public
> + * License version 2, as published by the Free Software Foundation, and
> + * may be copied, distributed, and modified under those terms.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#ifndef __ROCKCHIP_DRM_NOTIFY_H
> +#define __ROCKCHIP_DRM_NOTIFY_H
> +
> +#include <linux/notifier.h>
> +
> +enum vblank_enable_op {
> +	VBLANK_ENABLE = 0,
> +	VBLANK_DISABLE,
> +};
> +
> +void rockchip_drm_vblank_enable(void);
> +void rockchip_drm_vblank_disable(void);
> +int rockchip_drm_vblank_register_notifier(struct notifier_block *nb);
> +int rockchip_drm_vblank_unregister_notifier(struct notifier_block *nb);
> +
> +#endif /* __ROCKCHIP_DRM_NOTIFY_H */
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> index 257501f..fb6ce4b 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
> @@ -35,6 +35,7 @@
>  #include "rockchip_drm_gem.h"
>  #include "rockchip_drm_fb.h"
>  #include "rockchip_drm_vop.h"
> +#include "rockchip_drm_notify.h"
>  
>  #define __REG_SET_RELAXED(x, off, mask, shift, v, write_mask) \
>  		vop_mask_write(x, off, mask, shift, v, write_mask, true)
> @@ -851,6 +852,8 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
>  
>  	spin_unlock_irqrestore(&vop->irq_lock, flags);
>  
> +	rockchip_drm_vblank_enable();
> +
>  	return 0;
>  }
>  
> @@ -867,6 +870,8 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
>  	VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0);
>  
>  	spin_unlock_irqrestore(&vop->irq_lock, flags);
> +
> +	rockchip_drm_vblank_disable();
>  }
>  
>  static void vop_crtc_wait_for_update(struct drm_crtc *crtc)
> -- 
> 1.9.1
> 
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


From daniel at ffwll.ch  Tue May 31 07:38:31 2016
From: daniel at ffwll.ch (Daniel Vetter)
Date: Tue, 31 May 2016 16:38:31 +0200
Subject: [RFC PATCH v1 0/2]
In-Reply-To: <1464701856-8695-1-git-send-email-ykk@rock-chips.com>
References: <1464701856-8695-1-git-send-email-ykk@rock-chips.com>
Message-ID: <20160531143831.GK7231@phenom.ffwll.local>

On Tue, May 31, 2016 at 09:37:36PM +0800, Yakir Yang wrote:
> The full name of PSR is Panel Self Refresh, panel device could refresh
> itself with the hardware framebuffer in panel, this would make a lots
> of sense to save the power consumption.
> 
> For example, when desktop haven't change the context for a long time,
> then we could refresh the data to the hardware framebuffer of panel,
> and then let panel enter into PSR mode. After that system could poweroff
> the LCDC controller and eDP controller, just let panel refresh the screen
> by itself.
> 
> It's hard to decide when panel should enter into PSR or exit from PSR, in
> this time I chose to let the drm_vblank enable/disable event driver the PSR.
> 
> This thread is based on Mark's RK3399 VOP thread[0] and my RK3399 eDP
> thread[1].
> 
> [0]: https://patchwork.kernel.org/patch/8886041/
> [1]: https://patchwork.kernel.org/patch/9132713/

Looks like you didn't wire up the drm_framebuffer->funcs->dirty callback
for manual upload of simple clients like bootsplash or fbdev. I think
that's needed. At least it's needed for every other manual upload dsi and
edp psr implementation.
-Daniel

> 
> - Yakir
> Thanks,
> 
> 
> Yakir Yang (2):
>   drm/rockchip: add a notify event about vblank enable/disable
>   drm/rockchip: analogix: add eDP PSR function
> 
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  69 ++++++++++++++
>  drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |   5 +
>  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  |  54 +++++++++++
>  drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  |  28 ++++++
>  drivers/gpu/drm/rockchip/Makefile                  |   2 +-
>  drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    |  65 +++++++++++++
>  drivers/gpu/drm/rockchip/rockchip_drm_notify.c     | 105 +++++++++++++++++++++
>  drivers/gpu/drm/rockchip/rockchip_drm_notify.h     |  33 +++++++
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |  96 +++++++++++++++++++
>  drivers/gpu/drm/rockchip/rockchip_drm_vop.h        |   3 +
>  drivers/gpu/drm/rockchip/rockchip_vop_reg.c        |   2 +
>  include/drm/bridge/analogix_dp.h                   |   3 +
>  12 files changed, 464 insertions(+), 1 deletion(-)
>  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.c
>  create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.h
> 
> -- 
> 1.9.1
> 
> 

-- 
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch


From dianders at chromium.org  Tue May 31 10:03:37 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 31 May 2016 10:03:37 -0700
Subject: [PATCH 2/5] clocksource: rockchip: remove unnecessary clear irq
 before request_irq
In-Reply-To: <574CC839.60608@linaro.org>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-3-git-send-email-wxt@rock-chips.com>
 <574CC839.60608@linaro.org>
Message-ID: <CAD=FV=U5zqU0CMeg1dDTYHrRqWAxTQO_xk2T7p09GJuj-Fn9Gw@mail.gmail.com>

Hi,

On Mon, May 30, 2016 at 4:09 PM, Daniel Lezcano
<daniel.lezcano at linaro.org> wrote:
> On 05/25/2016 11:49 AM, Caesar Wang wrote:
>>
>> From: Huang Tao <huangtao at rock-chips.com>
>>
>> rk_timer_interrupt_clear and rk_timer_disable is unnecessary before
>> request_irq. Timer should keep disabled before booting Linux.
>
>
> That's true in the perfect world :/ Some version has u-boot letting the
> timer with irq enabled, therefore as soon as request_irq is done, an irq
> fires and leads to a kernel panic.
>
> On the other side, this timer is not used on the other rockchip version than
> rk3399 because of no need of a broadcast timer, so removing these two lines
> may be acceptable.
>
> Can try the changes with another board, eg rk3288 (and forcing to use this
> timer). Can you do the test and confirm it does not break with different
> version of u-boot ?

Actually, I'm not even sure that's true in a perfect world.  ;)  There
are two main problems that might be lurking here:

1. On exynos5 devices I've worked with, the private timer (MCT)
actually shared the same physical counter with the ARM Architected
Timer.  IIRC stopping or resetting the MCT had the effect of stopping
/ resetting the Arch Timer.  Is it the same for you?  As I understand
it the Arch Timer isn't supposed to ever be stopped or reset.  If
firmware left the timer stopped and the kernel happened to be compiled
without support for the Rockchip timer (but had the Arch Timers) then
things would be very broken.  Also the early kernel boot might be
broken if the Arch Timer inits before the Rockchip timer.

NOTE: If your timer and the Arch Timer are totally separate then point
#1 is not important.


2. Historically in Chrome OS there's been an unofficial agreement that
the firmware would start its high speed timer as soon as possible at
bootup and that this could be used to (roughly) measure the time
between the start of firmware and the start of the kernel.  That means
that the kernel was expecting the timer to actually be running when it
started up.  Yup, this is a bit of a hack and I'm not sure it's
terribly well documented, but it does provide a reason that firmware
might have left the timer running.


-Doug


From broonie at kernel.org  Tue May 31 10:46:29 2016
From: broonie at kernel.org (Mark Brown)
Date: Tue, 31 May 2016 18:46:29 +0100
Subject: Applied "spi/rockchip: add the rk3036/rk3228/rk3368 to match for
 driver" to the spi tree
In-Reply-To: <1463672824-15367-2-git-send-email-wxt@rock-chips.com>
Message-ID: <E1b7nkL-0006By-NN@debutante>

The patch

   spi/rockchip: add the rk3036/rk3228/rk3368 to match for driver

has been applied to the spi tree at

   git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git 

All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.  

You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.

If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.

Please add any relevant lists and maintainers to the CCs when replying
to this mail.

Thanks,
Mark

>From aa29ea3df27dbba19ef59023d0f7330f2fdc58ae Mon Sep 17 00:00:00 2001
From: Caesar Wang <wxt at rock-chips.com>
Date: Fri, 20 May 2016 07:56:21 +0800
Subject: [PATCH] spi/rockchip: add the rk3036/rk3228/rk3368 to match for
 driver

In gerenal, the "rockchip,rockchip-spi" string will match the dts
that's great in spi driver. After all the most of rockchip SoCs ar
same spi controller.

Then, we should keep the old style to match the dts various.

Signed-off-by: Caesar Wang <wxt at rock-chips.com>
Signed-off-by: Mark Brown <broonie at kernel.org>
---
 drivers/spi/spi-rockchip.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index cd89682065b9..bead5bfcbb0c 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -892,9 +892,12 @@ static const struct dev_pm_ops rockchip_spi_pm = {
 };
 
 static const struct of_device_id rockchip_spi_dt_match[] = {
+	{ .compatible = "rockchip,rk3036-spi", },
 	{ .compatible = "rockchip,rk3066-spi", },
 	{ .compatible = "rockchip,rk3188-spi", },
+	{ .compatible = "rockchip,rk3228-spi", },
 	{ .compatible = "rockchip,rk3288-spi", },
+	{ .compatible = "rockchip,rk3368-spi", },
 	{ .compatible = "rockchip,rk3399-spi", },
 	{ },
 };
-- 
2.8.1



From dianders at chromium.org  Tue May 31 12:57:17 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 31 May 2016 12:57:17 -0700
Subject: [PATCH 2/6] Documentation: bindings: add dt doc for Rockchip USB
 Type-C PHY
In-Reply-To: <5748094F.6030204@rock-chips.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
 <1464328939-8073-3-git-send-email-zyw@rock-chips.com>
 <2812026.ptEv4ktvbn@phil> <5748094F.6030204@rock-chips.com>
Message-ID: <CAD=FV=W9iFXX_BfORP-9=8tnu9Ea_f2k1wK_T2j=ZAVA9cFSwg@mail.gmail.com>

Chris,

On Fri, May 27, 2016 at 1:46 AM, Chris Zhong <zyw at rock-chips.com> wrote:
> Hi Heiko
>
>
> On 05/27/2016 04:29 PM, Heiko Stuebner wrote:
>>
>> Hi Chris,
>>
>> Am Freitag, 27. Mai 2016, 14:02:15 schrieb Chris Zhong:
>>>
>>> This patch adds a binding that describes the Rockchip USB Type-C PHY
>>> for rk3399.
>>>
>>> Signed-off-by: Chris Zhong <zyw at rock-chips.com>
>>> ---
>>>
>>>   .../devicetree/bindings/phy/phy-rockchip-typec.txt | 55
>>> ++++++++++++++++++++++ 1 file changed, 55 insertions(+)
>>>   create mode 100644
>>> Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
>>> b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file
>>> mode 100644
>>> index 0000000..402f667
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
>>> @@ -0,0 +1,55 @@
>>> +ROCKCHIP type-c PHY
>>> +
>>> +Required properties:
>>> + - compatible: should be "rockchip,rk3399-typec-phy"
>>> + - reg : Address and length of the usb phy control register set
>>> + - rockchip,grf : phandle to the syscon managing the "general
>>> +   register files"
>>> + - clocks : phandle + clock specifier for the phy clocks
>>> + - clock-names: string, clock name, must be "tcpdcore", "tcpdphy_ref";
>>> + - resets : a list of phandle + reset specifier pairs
>>> + - reset-names : string reset name, must be:
>>> +                "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst"

In other contexts I believe Heiko has requested that a suffix like
"_rst" not be present in the names of reset signals.  We already know
that this is a list of reset names so the "_rst" is redundant.

>>> + - #phy-cells: Must be 0.  See ./phy-bindings.txt for details.
>>> + - rockchip,usb3phy*: phy registers embed in grf
>>> +
>>> +Example:
>>> +       tcphy0: phy at ff7c0000 {
>>> +               compatible = "rockchip,rk3399-typec-phy";
>>> +               reg = <0x0 0xff7c0000 0x0 0x40000>;
>>> +               #phy-cells = <0>;
>>> +               rockchip,grf = <&grf>;
>>> +               clocks = <&cru SCLK_UPHY0_TCPDCORE>,
>>> +                        <&cru SCLK_UPHY0_TCPDPHY_REF>;
>>> +               clock-names = "tcpdcore", "tcpdphy_ref";
>>> +               resets = <&cru SRST_UPHY0>,
>>> +                        <&cru SRST_UPHY0_PIPE_L00>,
>>> +                        <&cru SRST_P_UPHY0_TCPHY>;
>>> +               reset-names = "tcphy_rst", "tcphy_pipe_rst",
>>> "uphy_tcphy_rst";
>>> +               rockchip,usb3phy_con0 = <0x0e580 0 16>;
>>> +               rockchip,usb3phy_con1 = <0x0e584 0 16>;
>>> +               rockchip,usb3phy_con2 = <0x0e588 0 16>;
>>> +               rockchip,usb3phy_status0 = <0x0e5c0 0 13>;
>>> +               rockchip,usb3phy_status1 = <0x0e5c4 0 12>;
>>
>> please embedded this register data in the driver instead (not in the
>> devicetree), matched against the compatible value.
>> See Frank's usb2phy driver for reference if needed.
>
> Okay, I will move them to driver file next version, Thanks.

Just making sure: I saw a RESEND of your original version get posted,
but nothing that addresses Heiko's comments, right?

Also: note that bindings should be sent in the patch _before_ the
code.  So instead of:
  [1] phy: Add USB Type-C PHY driver for rk3399
  [2] Documentation: bindings: add dt doc for Rockchip USB Type-C PHY
  [3] drm/rockchip: vop: add cdn DP support for rk3399
  [4] Documentation: bindings: add dt documentation for cdn DP controller

You should have:
  [1] Documentation: bindings: add dt doc for Rockchip USB Type-C PHY
  [2] phy: Add USB Type-C PHY driver for rk3399
  [3] Documentation: bindings: add dt documentation for cdn DP controller
  [4] drm/rockchip: vop: add cdn DP support for rk3399


-Doug


From javier at osg.samsung.com  Tue May 31 13:01:15 2016
From: javier at osg.samsung.com (Javier Martinez Canillas)
Date: Tue, 31 May 2016 16:01:15 -0400
Subject: [PATCH v2 0/10] Add RK3399 eDP support and fix some bugs to
 analogix_dp driver.
In-Reply-To: <5747E648.6020100@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
 <5746C321.9000707@rock-chips.com>
 <4e1c65f8-5a5b-dbb9-35fe-ef09c0758536@osg.samsung.com>
 <5747E648.6020100@rock-chips.com>
Message-ID: <f6fb95e2-6357-5219-ea08-263c017955e4@osg.samsung.com>

Hello Yakir,

On 05/27/2016 02:16 AM, Yakir Yang wrote:
> Hi Javier,
> 
> On 05/26/2016 08:48 PM, Javier Martinez Canillas wrote:
>> Hello Yakir,
>>
>> On 05/26/2016 05:34 AM, Yakir Yang wrote:
>>> Hi Javier,
>>>
>>> On 05/24/2016 01:01 PM, Yakir Yang wrote:
>>>> Hi all,
>>>>
>>>> This series have been posted about one month, still no comments, help here :(
>>> This series works rightly on Rockchip platform, and most of them haven't touch the
>>> common analogix_dp driver (except for the hotplug fixed). So i guess Exynos platform
>>> should also happy with this changes.
>>>
>>> But not sure about that. So, is it possible that you could help to check this on Exynos
>>> Chromebook, if so i would be very grateful about that.
>>>
>> Of course, I' ll test. Could you please provide me a branch that I can
>> pull directly to avoid cherry-picking all the patches from the list?
>>   
> Ah, thanks a lot, I do have a tree https://github.com/yakir-Yang/linux/tree/fromlist/3399-edp
>

I tested your branch on an Exynos5800 Peach Pi Chromebook and display
is working correctly. So feel free to add for the whole series:

Tested-by: Javier Martinez Canillas <javier at osg.samsung.com>

Best regards,
-- 
Javier Martinez Canillas
Open Source Group
Samsung Research America


From dianders at chromium.org  Tue May 31 14:35:39 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 31 May 2016 14:35:39 -0700
Subject: [PATCH 1/6] phy: Add USB Type-C PHY driver for rk3399
In-Reply-To: <1464328939-8073-2-git-send-email-zyw@rock-chips.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
 <1464328939-8073-2-git-send-email-zyw@rock-chips.com>
Message-ID: <CAD=FV=V1qX_YTTygsz=v+p6BdG8VZcu8np2nDvm1NiJHDnf==g@mail.gmail.com>

Chris,

On Thu, May 26, 2016 at 11:02 PM, Chris Zhong <zyw at rock-chips.com> wrote:
> Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB
> Type-C PHY is designed to support the USB3 and DP applications. The
> PHY basically has two main components: USB3 and DisplyPort. USB3
> operates in SuperSpeed mode and the DP can operate at RBR, HBR and
> HBR2 data rates.
>
> Signed-off-by: Chris Zhong <zyw at rock-chips.com>
> ---
>
>  drivers/phy/Kconfig              |   7 +
>  drivers/phy/Makefile             |   1 +
>  drivers/phy/phy-rockchip-typec.c | 823 +++++++++++++++++++++++++++++++++++++++
>  3 files changed, 831 insertions(+)

This is a bit of a superficial review.  Hopefully we can find someone
to do something more thorough.


>  create mode 100644 drivers/phy/phy-rockchip-typec.c
>
> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
> index 26566db..dc388a3d 100644
> --- a/drivers/phy/Kconfig
> +++ b/drivers/phy/Kconfig
> @@ -351,6 +351,13 @@ config PHY_ROCKCHIP_DP
>         help
>           Enable this to support the Rockchip Display Port PHY.
>
> +config PHY_ROCKCHIP_TYPEC
> +       tristate "Rockchip TYPEC PHY Driver"
> +       depends on ARCH_ROCKCHIP && OF
> +       select GENERIC_PHY
> +       help
> +         Enable this to support the Rockchip USB TYPEC PHY.
> +
>  config PHY_ST_SPEAR1310_MIPHY
>         tristate "ST SPEAR1310-MIPHY driver"
>         select GENERIC_PHY
> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
> index 24596a9..91fa413 100644
> --- a/drivers/phy/Makefile
> +++ b/drivers/phy/Makefile
> @@ -39,6 +39,7 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)   += phy-qcom-apq8064-sata.o
>  obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
>  obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
>  obj-$(CONFIG_PHY_ROCKCHIP_DP)          += phy-rockchip-dp.o
> +obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
>  obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)    += phy-qcom-ipq806x-sata.o
>  obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)   += phy-spear1310-miphy.o
>  obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)   += phy-spear1340-miphy.o
> diff --git a/drivers/phy/phy-rockchip-typec.c b/drivers/phy/phy-rockchip-typec.c
> new file mode 100644
> index 0000000..6609cfb
> --- /dev/null
> +++ b/drivers/phy/phy-rockchip-typec.c
> @@ -0,0 +1,823 @@
> +/*
> + * Rockchip usb3 PHY driver
> + *
> + * Copyright (C) 2016 Kever Yang <kever.yang at rock-chips.com>
> + *                    Chris Zhong <zyw at rock-chips.com>
> + * Copyright (C) 2016 ROCKCHIP, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/clk-provider.h>
> +#include <linux/io.h>
> +#include <linux/iopoll.h>p
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_platform.h>
> +#include <linux/phy/phy.h>
> +#include <linux/platform_device.h>
> +#include <linux/reset.h>
> +#include <linux/regmap.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/delay.h>
> +#include <linux/phy/phy-rockchip-typec.h>
> +
> +#define ADDR_ADJ                       2
> +#define CMN_SSM_BANDGAP                        (0x21 << ADDR_ADJ)
> +#define CMN_SSM_BIAS                   (0x22 << ADDR_ADJ)
> +#define CMN_PLLSM0_PLLEN               (0x29 << ADDR_ADJ)
> +#define CMN_PLLSM0_PLLPRE              (0x2a << ADDR_ADJ)
> +#define CMN_PLLSM0_PLLVREF             (0x2b << ADDR_ADJ)
> +#define CMN_PLLSM0_PLLLOCK             (0x2c << ADDR_ADJ)
> +#define CMN_PLLSM1_PLLEN               (0x31 << ADDR_ADJ)
> +#define CMN_PLLSM1_PLLPRE              (0x32 << ADDR_ADJ)
> +#define CMN_PLLSM1_PLLVREF             (0x33 << ADDR_ADJ)
> +#define CMN_PLLSM1_PLLLOCK             (0x34 << ADDR_ADJ)
> +#define CMN_PLLSM1_USER_DEF_CTRL       (0x37 << ADDR_ADJ)
> +#define CMN_ICAL_OVRD                  (0xc1 << ADDR_ADJ)
> +#define CMN_PLL0_VCOCAL_OVRD           (0x83 << ADDR_ADJ)
> +#define CMN_PLL0_VCOCAL_INIT           (0x84 << ADDR_ADJ)
> +#define CMN_PLL0_VCOCAL_ITER           (0x85 << ADDR_ADJ)
> +#define CMN_PLL0_LOCK_REFCNT_START     (0x90 << ADDR_ADJ)
> +#define CMN_PLL0_LOCK_PLLCNT_START     (0x92 << ADDR_ADJ)
> +#define CMN_PLL0_LOCK_PLLCNT_THR       (0x93 << ADDR_ADJ)
> +#define CMN_PLL0_INTDIV                        (0x94 << ADDR_ADJ)
> +#define CMN_PLL0_FRACDIV               (0x95 << ADDR_ADJ)
> +#define CMN_PLL0_HIGH_THR              (0x96 << ADDR_ADJ)
> +#define CMN_PLL0_DSM_DIAG              (0x97 << ADDR_ADJ)
> +#define CMN_PLL0_SS_CTRL1              (0x98 << ADDR_ADJ)
> +#define CMN_PLL0_SS_CTRL2              (0x99 << ADDR_ADJ)
> +#define CMN_PLL1_VCOCAL_START          (0xa1 << ADDR_ADJ)
> +#define CMN_PLL1_VCOCAL_OVRD           (0xa3 << ADDR_ADJ)
> +#define CMN_PLL1_VCOCAL_INIT           (0xa4 << ADDR_ADJ)
> +#define CMN_PLL1_VCOCAL_ITER           (0xa5 << ADDR_ADJ)
> +#define CMN_PLL1_LOCK_REFCNT_START     (0xb0 << ADDR_ADJ)
> +#define CMN_PLL1_LOCK_PLLCNT_START     (0xb2 << ADDR_ADJ)
> +#define CMN_PLL1_LOCK_PLLCNT_THR       (0xb3 << ADDR_ADJ)
> +#define CMN_PLL1_INTDIV                        (0xb4 << ADDR_ADJ)
> +#define CMN_PLL1_FRACDIV               (0xb5 << ADDR_ADJ)
> +#define CMN_PLL1_HIGH_THR              (0xb6 << ADDR_ADJ)
> +#define CMN_PLL1_DSM_DIAG              (0xb7 << ADDR_ADJ)
> +#define CMN_PLL1_SS_CTRL1              (0xb8 << ADDR_ADJ)
> +#define CMN_PLL1_SS_CTRL2              (0xb9 << ADDR_ADJ)
> +#define CMN_RXCAL_OVRD                 (0xd1 << ADDR_ADJ)
> +#define CMN_TXPUCAL_CTRL               (0xe0 << ADDR_ADJ)
> +#define CMN_TXPUCAL_OVRD               (0xe1 << ADDR_ADJ)
> +#define CMN_TXPDCAL_OVRD               (0xf1 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_FBH_OVRD         (0x1c0 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_FBL_OVRD         (0x1c1 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_OVRD             (0x1c2 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_V2I_TUNE         (0x1c5 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_CP_TUNE          (0x1c6 << ADDR_ADJ)
> +#define CMN_DIAG_PLL0_LF_PROG          (0x1c7 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_FBH_OVRD         (0x1d0 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_FBL_OVRD         (0x1d1 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_OVRD             (0x1d2 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_V2I_TUNE         (0x1d5 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_CP_TUNE          (0x1d6 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_LF_PROG          (0x1d7 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_PTATIS_TUNE1     (0x1d8 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_PTATIS_TUNE2     (0x1d9 << ADDR_ADJ)
> +#define CMN_DIAG_PLL1_INCLK_CTRL       (0x1da << ADDR_ADJ)
> +#define CMN_DIAG_HSCLK_SEL             (0x1e0 << ADDR_ADJ)
> +
> +#define XCVR_PSM_RCTRL(n)              ((0x4001 | (n << 9)) << ADDR_ADJ)
> +#define XCVR_PSM_CAL_TMR(n)            ((0x4002 | (n << 9)) << ADDR_ADJ)
> +#define XCVR_PSM_A0IN_TMR(n)           ((0x4003 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_CAL_SCLR_MULT(n)       ((0x4047 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_CPOST_MULT_00(n)       ((0x404c | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_CPOST_MULT_01(n)       ((0x404d | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_CPOST_MULT_10(n)       ((0x404e | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_CPOST_MULT_11(n)       ((0x404f | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_000(n)      ((0x4050 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_001(n)      ((0x4051 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_010(n)      ((0x4052 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_011(n)      ((0x4053 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_100(n)      ((0x4054 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_101(n)      ((0x4055 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_110(n)      ((0x4056 | (n << 9)) << ADDR_ADJ)
> +#define TX_TXCC_MGNFS_MULT_111(n)      ((0x4057 | (n << 9)) << ADDR_ADJ)
> +#define XCVR_DIAG_PLLDRC_CTRL(n)       ((0x40e0 | (n << 9)) << ADDR_ADJ)
> +#define XCVR_DIAG_BIDI_CTRL(n)         ((0x40e8 | (n << 9)) << ADDR_ADJ)
> +#define XCVR_DIAG_LANE_FCM_EN_MGN(n)   ((0x40f2 | (n << 9)) << ADDR_ADJ)
> +#define TX_PSC_A0(n)                   ((0x4100 | (n << 9)) << ADDR_ADJ)
> +#define TX_PSC_A1(n)                   ((0x4101 | (n << 9)) << ADDR_ADJ)
> +#define TX_PSC_A2(n)                   ((0x4102 | (n << 9)) << ADDR_ADJ)
> +#define TX_PSC_A3(n)                   ((0x4103 | (n << 9)) << ADDR_ADJ)
> +#define TX_RCVDET_CTRL(n)              ((0x4120 | (n << 9)) << ADDR_ADJ)
> +#define TX_RCVDET_EN_TMR(n)            ((0x4122 | (n << 9)) << ADDR_ADJ)
> +#define TX_RCVDET_ST_TMR(n)            ((0x4123 | (n << 9)) << ADDR_ADJ)
> +#define TX_DIAG_TX_DRV(n)              ((0x41e1 | (n << 9)) << ADDR_ADJ)
> +#define TX_DIAG_BGREF_PREDRV_DELAY     (0x41e7 << ADDR_ADJ)
> +#define TX_ANA_CTRL_REG_1              (0x5020 << ADDR_ADJ)
> +#define TX_ANA_CTRL_REG_2              (0x5021 << ADDR_ADJ)
> +#define TXDA_COEFF_CALC_CTRL           (0x5022 << ADDR_ADJ)
> +#define TX_DIG_CTRL_REG_2              (0x5024 << ADDR_ADJ)
> +#define TXDA_CYA_AUXDA_CYA             (0x5025 << ADDR_ADJ)
> +#define TX_ANA_CTRL_REG_3              (0x5026 << ADDR_ADJ)
> +#define TX_ANA_CTRL_REG_4              (0x5027 << ADDR_ADJ)
> +#define TX_ANA_CTRL_REG_5              (0x5029 << ADDR_ADJ)
> +
> +#define RX_PSC_A0(n)                   ((0x8000 | (n << 9)) << ADDR_ADJ)
> +#define RX_PSC_A1(n)                   ((0x8001 | (n << 9)) << ADDR_ADJ)
> +#define RX_PSC_A2(n)                   ((0x8002 | (n << 9)) << ADDR_ADJ)
> +#define RX_PSC_A3(n)                   ((0x8003 | (n << 9)) << ADDR_ADJ)
> +#define RX_PSC_CAL(n)                  ((0x8006 | (n << 9)) << ADDR_ADJ)
> +#define RX_PSC_RDY(n)                  ((0x8007 | (n << 9)) << ADDR_ADJ)
> +#define RX_IQPI_ILL_CAL_OVRD           (0x8023 << ADDR_ADJ)
> +#define RX_EPI_ILL_CAL_OVRD            (0x8033 << ADDR_ADJ)
> +#define RX_SDCAL0_OVRD                 (0x8041 << ADDR_ADJ)
> +#define RX_SDCAL1_OVRD                 (0x8049 << ADDR_ADJ)
> +#define RX_SLC_INIT                    (0x806d << ADDR_ADJ)
> +#define RX_SLC_RUN                     (0x806e << ADDR_ADJ)
> +#define RX_CDRLF_CNFG2                 (0x8081 << ADDR_ADJ)
> +#define RX_SIGDET_HL_FILT_TMR(n)       ((0x8090 | (n << 9)) << ADDR_ADJ)
> +#define RX_SLC_IOP0_OVRD               (0x8101 << ADDR_ADJ)
> +#define RX_SLC_IOP1_OVRD               (0x8105 << ADDR_ADJ)
> +#define RX_SLC_QOP0_OVRD               (0x8109 << ADDR_ADJ)
> +#define RX_SLC_QOP1_OVRD               (0x810d << ADDR_ADJ)
> +#define RX_SLC_EOP0_OVRD               (0x8111 << ADDR_ADJ)
> +#define RX_SLC_EOP1_OVRD               (0x8115 << ADDR_ADJ)
> +#define RX_SLC_ION0_OVRD               (0x8119 << ADDR_ADJ)
> +#define RX_SLC_ION1_OVRD               (0x811d << ADDR_ADJ)
> +#define RX_SLC_QON0_OVRD               (0x8121 << ADDR_ADJ)
> +#define RX_SLC_QON1_OVRD               (0x8125 << ADDR_ADJ)
> +#define RX_SLC_EON0_OVRD               (0x8129 << ADDR_ADJ)
> +#define RX_SLC_EON1_OVRD               (0x812d << ADDR_ADJ)
> +#define RX_SLC_IEP0_OVRD               (0x8131 << ADDR_ADJ)
> +#define RX_SLC_IEP1_OVRD               (0x8135 << ADDR_ADJ)
> +#define RX_SLC_QEP0_OVRD               (0x8139 << ADDR_ADJ)
> +#define RX_SLC_QEP1_OVRD               (0x813d << ADDR_ADJ)
> +#define RX_SLC_EEP0_OVRD               (0x8141 << ADDR_ADJ)
> +#define RX_SLC_EEP1_OVRD               (0x8145 << ADDR_ADJ)
> +#define RX_SLC_IEN0_OVRD               (0x8149 << ADDR_ADJ)
> +#define RX_SLC_IEN1_OVRD               (0x814d << ADDR_ADJ)
> +#define RX_SLC_QEN0_OVRD               (0x8151 << ADDR_ADJ)
> +#define RX_SLC_QEN1_OVRD               (0x8155 << ADDR_ADJ)
> +#define RX_SLC_EEN0_OVRD               (0x8159 << ADDR_ADJ)
> +#define RX_SLC_EEN1_OVRD               (0x815d << ADDR_ADJ)
> +#define RX_DIAG_SIGDET_TUNE(n)         ((0x81dc | (n << 9)) << ADDR_ADJ)
> +#define RX_DIAG_SC2C_DELAY             (0x81e1 << ADDR_ADJ)
> +
> +#define PMA_LANE_CFG                   (0xc000 << ADDR_ADJ)
> +#define PIPE_CMN_CTRL1                 (0xc001 << ADDR_ADJ)
> +#define PIPE_CMN_CTRL2                 (0xc002 << ADDR_ADJ)
> +#define PIPE_COM_LOCK_CFG1             (0xc003 << ADDR_ADJ)
> +#define PIPE_COM_LOCK_CFG2             (0xc004 << ADDR_ADJ)
> +#define PIPE_RCV_DET_INH               (0xc005 << ADDR_ADJ)
> +#define DP_MODE_CTL                    (0xc008 << ADDR_ADJ)
> +#define DP_CLK_CTL                     (0xc009 << ADDR_ADJ)
> +#define STS                            (0xc00F << ADDR_ADJ)
> +#define PHY_ISO_CMN_CTRL               (0xc010 << ADDR_ADJ)
> +#define PHY_DP_TX_CTL                  (0xc408 << ADDR_ADJ)
> +#define PMA_CMN_CTRL1                  (0xc800 << ADDR_ADJ)
> +#define PHY_PMA_ISO_CMN_CTRL           (0xc810 << ADDR_ADJ)
> +#define PHY_ISOLATION_CTRL             (0xc81f << ADDR_ADJ)
> +#define PHY_PMA_ISO_XCVR_CTRL(n)       ((0xcc11 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_LINK_MODE(n)       ((0xcc12 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_PWRST_CTRL(n)      ((0xcc13 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_TX_DATA_LO(n)      ((0xcc14 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_TX_DATA_HI(n)      ((0xcc15 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_RX_DATA_LO(n)      ((0xcc16 | (n << 6)) << ADDR_ADJ)
> +#define PHY_PMA_ISO_RX_DATA_HI(n)      ((0xcc17 | (n << 6)) << ADDR_ADJ)
> +#define TX_BIST_CTRL(n)                        ((0x4140 | (n << 9)) << ADDR_ADJ)
> +#define TX_BIST_UDDWR(n)               ((0x4141 | (n << 9)) << ADDR_ADJ)
> +
> +#define GRF_SOC_CON26                  0x6268
> +#define UPHY_DP_SEL                    BIT(3)
> +#define UPHY_DP_SEL_MASK               BIT(19)
> +#define DPTX_HDP_SEL                   (3 << 12)
> +#define DPTX_HDP_SEL_MASK              (3 << 28)
> +
> +#define PHY_MODE_SET_TIMEOUT           1000000
> +
> +#define        MODE_DISCONNECT                 1
> +#define        MODE_UFP                        2
> +#define        MODE_DFP_USBONLY                3
> +#define        MODE_DFP_DPONLY                 4
> +#define        MODE_DFP_USB3DP                 5
> +#define        MODE_DFP_USB2DP                 6
> +
> +#define PARSE_GRF_REG(TYPE) { \
> +       if (of_find_property(np, "rockchip,usb3phy_"#TYPE, &len)) { \
> +               len /= sizeof(u32);\
> +               ret = of_property_read_u32_array(np, "rockchip,usb3phy_" #TYPE,\
> +                                                array, len); \
> +               exregs->usb3phy_##TYPE = array[0]; \
> +               exregs->usb3phy_##TYPE##_shift = array[1]; \
> +               exregs->usb3phy_##TYPE##_mask = array[2]; \
> +               pr_info("%s property found %s, %x, %d, %d\n", __func__, \
> +                       "rockchip,usb3phy_"#TYPE, \
> +                       array[0], array[1], array[2]); \
> +       } else { \
> +               pr_info("%s property not found %s\n", __func__, \
> +                       "rockchip,usb3phy_" #TYPE); \
> +       } \
> +}
> +
> +struct rockchip_typec_phy *rockchip_tcphy;

Unused global?

> +
> +static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy,
> +                         unsigned int num_lanes)
> +{
> +       unsigned int i;()?
> +
> +       writel(0x830, tcphy->base + PMA_CMN_CTRL1);
> +       for (i = 0; i < num_lanes; i++) {
> +               writel(0x90, tcphy->base + XCVR_DIAG_LANE_FCM_EN_MGN(i));
> +               writel(0x960, tcphy->base + TX_RCVDET_EN_TMR(i));
> +               writel(0x30, tcphy->base + TX_RCVDET_ST_TMR(i));

Would it be too much to ask to get more details about all these magic values?

> +       }
> +}
> +
> +static void tcphy_cfg_usb_pll(struct rockchip_typec_phy *tcphy)
> +{
> +       unsigned int rdata;
> +
> +       rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
> +       writel(rdata & 0xfffc, tcphy->base + CMN_DIAG_HSCLK_SEL);
> +       writel(0xf0, tcphy->base + CMN_PLL0_VCOCAL_INIT);
> +       writel(0x18, tcphy->base + CMN_PLL0_VCOCAL_ITER);
> +       writel(0xd0, tcphy->base + CMN_PLL0_INTDIV);
> +       writel(0x4a4a, tcphy->base + CMN_PLL0_FRACDIV);
> +       writel(0x34, tcphy->base + CMN_PLL0_HIGH_THR);
> +       writel(0x1ee, tcphy->base + CMN_PLL0_SS_CTRL1);
> +       writel(0x7f03, tcphy->base + CMN_PLL0_SS_CTRL2);
> +       writel(0x20, tcphy->base + CMN_PLL0_DSM_DIAG);
> +       writel(0, tcphy->base + CMN_DIAG_PLL0_OVRD);
> +       writel(0, tcphy->base + CMN_DIAG_PLL0_FBH_OVRD);
> +       writel(0, tcphy->base + CMN_DIAG_PLL0_FBL_OVRD);
> +       writel(0x7, tcphy->base + CMN_DIAG_PLL0_V2I_TUNE);
> +       writel(0x45, tcphy->base + CMN_DIAG_PLL0_CP_TUNE);
> +       writel(0x8, tcphy->base + CMN_DIAG_PLL0_LF_PROG);
> +}
> +
> +static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy)
> +{
> +       unsigned int rdata;
> +
> +       writel(0x2405, tcphy->base + DP_CLK_CTL);
> +
> +       rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
> +       rdata = (rdata & 0xffcf) | 0x30;
> +       writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL);
> +       writel(0xf0, tcphy->base + CMN_PLL1_VCOCAL_INIT);
> +       writel(0x18, tcphy->base + CMN_PLL1_VCOCAL_ITER);
> +       writel(0x30b9, tcphy->base + CMN_PLL1_VCOCAL_START);
> +       writel(0x21c, tcphy->base + CMN_PLL1_INTDIV);
> +       writel(0, tcphy->base + CMN_PLL1_FRACDIV);
> +       writel(0x5, tcphy->base + CMN_PLL1_HIGH_THR);
> +       writel(0x35, tcphy->base + CMN_PLL1_SS_CTRL1);
> +       writel(0x7f1e, tcphy->base + CMN_PLL1_SS_CTRL2);
> +       writel(0x20, tcphy->base + CMN_PLL1_DSM_DIAG);
> +       writel(0, tcphy->base + CMN_PLLSM1_USER_DEF_CTRL);
> +       writel(0, tcphy->base + CMN_DIAG_PLL1_OVRD);
> +       writel(0, tcphy->base + CMN_DIAG_PLL1_FBH_OVRD);
> +       writel(0, tcphy->base + CMN_DIAG_PLL1_FBL_OVRD);
> +       writel(0x6, tcphy->base + CMN_DIAG_PLL1_V2I_TUNE);
> +       writel(0x45, tcphy->base + CMN_DIAG_PLL1_CP_TUNE);
> +       writel(0x8, tcphy->base + CMN_DIAG_PLL1_LF_PROG);
> +       writel(0x100, tcphy->base + CMN_DIAG_PLL1_PTATIS_TUNE1);
> +       writel(0x7, tcphy->base + CMN_DIAG_PLL1_PTATIS_TUNE2);
> +       writel(0x4, tcphy->base + CMN_DIAG_PLL1_INCLK_CTRL);
> +}
> +
> +static void tcphy_tx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
> +                                 unsigned int lane)
> +{
> +       writel(0x7799, tcphy->base + TX_PSC_A0(lane));
> +       writel(0x7798, tcphy->base + TX_PSC_A1(lane));
> +       writel(0x5098, tcphy->base + TX_PSC_A2(lane));
> +       writel(0x5098, tcphy->base + TX_PSC_A3(lane));
> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
> +       writel(0xbf, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
> +}
> +
> +static void tcphy_rx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
> +                                 unsigned int lane)
> +{
> +       writel(0xa6fd, tcphy->base + RX_PSC_A0(lane));
> +       writel(0xa6fd, tcphy->base + RX_PSC_A1(lane));
> +       writel(0xa410, tcphy->base + RX_PSC_A2(lane));
> +       writel(0x2410, tcphy->base + RX_PSC_A3(lane));
> +       writel(0x23ff, tcphy->base + RX_PSC_CAL(lane));
> +       writel(0x13, tcphy->base + RX_SIGDET_HL_FILT_TMR(lane));
> +       writel(0x1004, tcphy->base + RX_DIAG_SIGDET_TUNE(lane));
> +       writel(0x2010, tcphy->base + RX_PSC_RDY(lane));
> +       writel(0xfb, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
> +}
> +
> +static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy,
> +                             unsigned int lane)
> +{
> +       unsigned int rdata;
> +
> +       writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane));
> +       writel(0x6799, tcphy->base + TX_PSC_A0(lane));
> +       writel(0x6798, tcphy->base + TX_PSC_A1(lane));
> +       writel(0x98, tcphy->base + TX_PSC_A2(lane));
> +       writel(0x98, tcphy->base + TX_PSC_A3(lane));
> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_001(lane));
> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_010(lane));
> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_011(lane));
> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_100(lane));
> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_101(lane));
> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_110(lane));
> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_111(lane));
> +
> +       writel(0, tcphy->base + TX_TXCC_CPOST_MULT_10(lane));
> +       writel(0, tcphy->base + TX_TXCC_CPOST_MULT_01(lane));
> +       writel(0, tcphy->base + TX_TXCC_CPOST_MULT_00(lane));
> +       writel(0, tcphy->base + TX_TXCC_CPOST_MULT_11(lane));
> +
> +       writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane));
> +       writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane));
> +
> +       rdata = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
> +       rdata = (rdata & 0x8fff) | 0x6000;
> +       writel(rdata, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
> +}
> +
> +static void tcphy_cfg_pin_assign(struct rockchip_typec_phy *tcphy)
> +{
> +       switch (tcphy->map) {
> +       case PIN_MAP_A:
> +               writel(0x19d5, tcphy->base + PMA_LANE_CFG);
> +               break;
> +       case PIN_MAP_B:
> +               writel(0x1500, tcphy->base + PMA_LANE_CFG);
> +               break;
> +       case PIN_MAP_C:
> +       case PIN_MAP_E:
> +               writel(0x51d9, tcphy->base + PMA_LANE_CFG);
> +               break;
> +       case PIN_MAP_D:
> +       case PIN_MAP_F:
> +               writel(0x5100, tcphy->base + PMA_LANE_CFG);
> +               break;
> +       };
> +}
> +
> +static void tcphy_cfg_lanes(struct rockchip_typec_phy *tcphy,
> +                           unsigned int link_cfg)
> +{
> +       unsigned int i;
> +
> +       /* PMA lane configuration DP or USB3 */
> +       for (i = 0; i < 4; i++) {
> +               if ((link_cfg >> i) & 0x1) {
> +                       tcphy_dp_cfg_lane(tcphy, i);
> +               } else {
> +                       /*
> +                        * lan0 TX and lan1 RX for USB3 Normal direction
> +                        * lan3 TX and lan2 RX for USB3 Flip direction
> +                        */
> +                       if ((i == 0) | (i == 3))
> +                               tcphy_tx_usb_cfg_lane(tcphy, i);
> +                       else
> +                               tcphy_rx_usb_cfg_lane(tcphy, i);
> +               }
> +       }
> +}
> +
> +static void tcphy_cfg_flip_set(struct rockchip_typec_phy *tcphy)
> +{
> +       regmap_write(tcphy->grf_regs,
> +                    tcphy->exregs.usb3phy_con0,
> +                    tcphy->flip | BIT(16));
> +
> +       tcphy_cfg_24m(tcphy, 0x4);
> +
> +       if (tcphy->mode == MODE_UFP ||
> +           tcphy->mode == MODE_DFP_USBONLY ||
> +           tcphy->mode == MODE_DFP_USB3DP)
> +               tcphy_cfg_usb_pll(tcphy);
> +
> +       if (tcphy->mode == MODE_DFP_DPONLY ||
> +           tcphy->mode == MODE_DFP_USB2DP ||
> +           tcphy->mode == MODE_DFP_USB3DP)
> +               tcphy_cfg_dp_pll(tcphy);
> +
> +       if (tcphy->mode == MODE_DFP_DPONLY || tcphy->mode == MODE_DFP_USB2DP)
> +               tcphy_cfg_lanes(tcphy, 0xf);
> +       else if (tcphy->flip)
> +               tcphy_cfg_lanes(tcphy, 0x3);
> +       else
> +               tcphy_cfg_lanes(tcphy, 0xc);
> +}
> +
> +static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
> +{
> +       int rdata, rdata2, val;
> +
> +       rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
> +       rdata2 = readl(tcphy->base + CMN_TXPUCAL_CTRL);
> +
> +       rdata = rdata & 0xdfff;
> +       writel(rdata, tcphy->base + TX_ANA_CTRL_REG_1);
> +
> +       rdata = readl(tcphy->base + TX_DIG_CTRL_REG_2);
> +       rdata = rdata & 0xffc0;
> +       rdata2 = rdata2 & 0x3f;
> +       rdata  = rdata | rdata2;
> +       writel(rdata, tcphy->base + TX_DIG_CTRL_REG_2);
> +       usleep_range(1000, 2000);

nit: this is at init time and will be run once.  Power savings of
trying to group wakeups will be minimal or none.  Last I looked
usleep_range() nearly always takes the longer of the two times unless
it happens to wake up anyway.  Make the range smaller and boot time
will be 1ms faster.  Try usleep_range(1000, 1050).

> +
> +       rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
> +       rdata = rdata | 0x2000;
> +       writel(rdata, tcphy->base + TX_ANA_CTRL_REG_1);
> +
> +       usleep_range(150, 200);
> +
> +       writel(0, tcphy->base + PHY_DP_TX_CTL);
> +       writel(0x100, tcphy->base + TX_ANA_CTRL_REG_2);
> +       writel(0x300, tcphy->base + TX_ANA_CTRL_REG_2);
> +       writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
> +       writel(0x2008, tcphy->base + TX_ANA_CTRL_REG_1);
> +       writel(0x2018, tcphy->base + TX_ANA_CTRL_REG_1);
> +       writel(0x30C, tcphy->base + TX_ANA_CTRL_REG_2);
> +       writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
> +       writel(0x1001, tcphy->base + TX_ANA_CTRL_REG_4);
> +       writel(0x2098, tcphy->base + TX_ANA_CTRL_REG_1);
> +       writel(0x2198, tcphy->base + TX_ANA_CTRL_REG_1);
> +       writel(0x30d, tcphy->base + TX_ANA_CTRL_REG_2);
> +       writel(0x30f, tcphy->base + TX_ANA_CTRL_REG_2);
> +
> +       if (tcphy->flip)
> +               writel(0xa078, tcphy->base + TX_ANA_CTRL_REG_1);
> +       else
> +               writel(0xb078, tcphy->base + TX_ANA_CTRL_REG_1);
> +
> +       writel(0x303, tcphy->base + TX_ANA_CTRL_REG_2);
> +       writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
> +       writel(0, tcphy->base + TX_ANA_CTRL_REG_4);
> +       writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
> +       writel(4, tcphy->base + TXDA_COEFF_CALC_CTRL);
> +       writel(0, tcphy->base + TXDA_CYA_AUXDA_CYA);
> +
> +       val = readl(tcphy->base + TX_DIG_CTRL_REG_2);
> +       val |= BIT(15);
> +       writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
> +}
> +
> +static void tcphy_dp_hpd(struct rockchip_typec_phy *tcphy,
> +                        u8 mode)
> +{
> +       /* force hpd */
> +       if (mode)
> +               regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
> +                            DPTX_HDP_SEL_MASK | DPTX_HDP_SEL);
> +       else
> +               regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
> +                            DPTX_HDP_SEL_MASK);
> +}
> +
> +static int tcphy_usb3_init(struct rockchip_typec_phy *tcphy)
> +{
> +       int timeout = 0;
> +       int ret, val;
> +
> +       /*wait TCPHY for pipe ready */
> +       while (1) {
> +               ret = regmap_read(tcphy->grf_regs,
> +                                 tcphy->exregs.usb3phy_status0, &val);
> +               val >>= tcphy->exregs.usb3phy_status0_shift;
> +               if ((val & 0x1) == 0)
> +                       break;
> +
> +               timeout++;
> +               if (timeout > 1000) {
> +                       pr_warn("%s wait pipe ready timerout!\n", __func__);
> +                       break;
> +               }
> +               usleep_range(10, 20);
> +       }
> +
> +       return 0;
> +}
> +
> +static int tcphy_dp_init(struct rockchip_typec_phy *tcphy)
> +{
> +       int ret, val;
> +
> +       ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
> +                                val, val & BIT(6), 1000, PHY_MODE_SET_TIMEOUT);
> +       if (ret < 0) {
> +               dev_err(tcphy->dev, "failed to wait TCPHY for DP ready\n");
> +               return -EBUSY;
> +       }
> +
> +       tcphy_dp_aux_calibration(tcphy);
> +
> +       if (tcphy->mode == MODE_DFP_USB3DP)
> +               writel(0xc101, tcphy->base + DP_MODE_CTL);
> +       else
> +               writel(0x0101, tcphy->base + DP_MODE_CTL);
> +
> +       ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
> +                                val, val & BIT(4), 1000, PHY_MODE_SET_TIMEOUT);
> +       if (ret < 0) {
> +               dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n");
> +               return -EBUSY;
> +       }
> +
> +       return 0;
> +}
> +
> +static int tcphy_phy_init(struct rockchip_typec_phy *tcphy)
> +{
> +       int ret;
> +       int timeout = 0;
> +
> +       ret = clk_prepare_enable(tcphy->clk_core);
> +       if (ret) {
> +               dev_err(tcphy->dev, "Failed to prepare_enable core clock\n");
> +               return ret;
> +       }
> +
> +       ret = clk_prepare_enable(tcphy->clk_ref);
> +       if (ret) {
> +               dev_err(tcphy->dev, "Failed to prepare_enable ref clock\n");
> +               return ret;
> +       }
> +
> +       /* select external psm clock */
> +       regmap_write(tcphy->grf_regs, tcphy->exregs.usb3phy_con2,
> +                    BIT(14) | BIT(30));
> +       regmap_write(tcphy->grf_regs, tcphy->exregs.usb3phy_con0, BIT(19));
> +
> +       reset_control_assert(tcphy->phy_rst);
> +       reset_control_assert(tcphy->pipe_rst);
> +       reset_control_assert(tcphy->uphy_rst);
> +
> +       if (tcphy->num == TYPEC_PHY0)
> +               regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
> +                            UPHY_DP_SEL_MASK);
> +       else
> +               regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
> +                            UPHY_DP_SEL_MASK | UPHY_DP_SEL);
> +
> +       reset_control_deassert(tcphy->uphy_rst);
> +
> +       tcphy_cfg_flip_set(tcphy);
> +
> +       tcphy_cfg_pin_assign(tcphy);
> +
> +       if (tcphy->mode == MODE_DFP_USB3DP)
> +               writel(0xc104, tcphy->base + DP_MODE_CTL);
> +       else if ((tcphy->mode == MODE_DFP_DPONLY) ||
> +                (tcphy->mode == MODE_DFP_USB2DP))
> +               writel(0x0104, tcphy->base + DP_MODE_CTL);
> +
> +       reset_control_deassert(tcphy->phy_rst);
> +
> +       while (!(readl(tcphy->base + PMA_CMN_CTRL1) & 1)) {
> +               timeout++;
> +               if (timeout > 1000)
> +                       break;
> +               usleep_range(10, 20);
> +       }
> +
> +       reset_control_deassert(tcphy->pipe_rst);
> +
> +       return 0;
> +}
> +
> +static int tcphy_phy_deinit(struct rockchip_typec_phy *tcphy)
> +{
> +       clk_disable_unprepare(tcphy->clk_core);
> +       clk_disable_unprepare(tcphy->clk_ref);
> +
> +       return 0;
> +}
> +
> +int tcphy_register_notifier(struct phy *_phy, struct notifier_block *nb)

Is there a reason this isn't static?

> +{
> +       struct rockchip_typec_phy *tcphy = phy_get_drvdata(_phy);
> +
> +       return atomic_notifier_chain_register(&tcphy->notifier, nb);
> +}
> +
> +void tcphy_unregister_notifier(struct phy *_phy,
> +                              struct notifier_block *nb)

Is there a reason this isn't static?

> +{
> +       struct rockchip_typec_phy *tcphy = phy_get_drvdata(_phy);
> +
> +       atomic_notifier_chain_unregister(&tcphy->notifier, nb);
> +}
> +
> +void tcphy_notifier_call_chain(struct rockchip_typec_phy *x,
> +                              unsigned long val, void *v)
> +{
> +       atomic_notifier_call_chain(&x->notifier, val, v);
> +}
> +EXPORT_SYMBOL_GPL(tcphy_notifier_call_chain);
> +
> +static int tcphy_pd_event(struct notifier_block *nb,
> +                         unsigned long event, void *priv)
> +{
> +       struct rockchip_typec_phy *tcphy;
> +       int value = *(int *)priv;
> +       u8 is_dp, dfp;
> +
> +       tcphy = container_of(nb, struct rockchip_typec_phy, event_nb);
> +       if (IS_ERR_OR_NULL(tcphy)) {
> +               pr_err("initialization issue");
> +               return -1;
> +       }
> +
> +       tcphy->flip = GET_FLIP(value);
> +       dfp = GET_DFP(value);
> +       is_dp = GET_DP(value);
> +       tcphy->map = GET_PIN_MAP(value);
> +
> +       if (event == 0) {
> +               if (tcphy->mode == MODE_DISCONNECT)
> +                       return 0;
> +               tcphy->mode = MODE_DISCONNECT;
> +       } else if (is_dp) {
> +               if (tcphy->map & (PIN_MAP_B | PIN_MAP_D | PIN_MAP_F))
> +                       tcphy->mode = MODE_DFP_USB3DP;
> +               else
> +                       tcphy->mode = MODE_DFP_DPONLY;
> +       } else if (dfp) {
> +               tcphy->mode = MODE_DFP_USBONLY;
> +       } else {
> +               tcphy->mode = MODE_UFP;
> +       }
> +
> +       schedule_delayed_work_on(0, &tcphy->event_wq, 0);
> +
> +       return 0;
> +}
> +
> +static void tcphy_event_wq(struct work_struct *work)
> +{
> +       struct rockchip_typec_phy *tcphy;
> +
> +       tcphy = container_of(work, struct rockchip_typec_phy, event_wq.work);
> +       if (IS_ERR_OR_NULL(tcphy)) {
> +               pr_err("initialization issue");
> +               return;
> +       }
> +
> +       switch (tcphy->mode) {
> +       case MODE_DISCONNECT:
> +               /* phy enter low power mode */
> +               tcphy_phy_deinit(tcphy);
> +               tcphy_dp_hpd(tcphy, 0);
> +               break;
> +       case MODE_UFP:
> +               tcphy_phy_init(tcphy);
> +               tcphy_usb3_init(tcphy);
> +               tcphy_dp_hpd(tcphy, 0);
> +               break;
> +       case MODE_DFP_USBONLY:
> +               tcphy_phy_init(tcphy);
> +               tcphy_usb3_init(tcphy);
> +               tcphy_dp_hpd(tcphy, 0);
> +               break;
> +       case MODE_DFP_DPONLY:
> +       case MODE_DFP_USB2DP:
> +               tcphy_phy_init(tcphy);
> +               tcphy_dp_init(tcphy);
> +               tcphy_dp_hpd(tcphy, 1);
> +               break;
> +       case MODE_DFP_USB3DP:
> +               tcphy_phy_init(tcphy);
> +               tcphy_usb3_init(tcphy);
> +               tcphy_dp_init(tcphy);
> +               tcphy_dp_hpd(tcphy, 1);
> +               break;
> +       }
> +}
> +
> +int tcphy_parse_reg(struct rockchip_typec_phy *tcphy, struct device *dev)
> +{
> +       struct tcphy_grf_reg *exregs = &tcphy->exregs;
> +       struct device_node *np = dev->of_node;
> +       u32 len = 0, array[3];
> +       int ret = 0;
> +
> +       PARSE_GRF_REG(con0);
> +       PARSE_GRF_REG(con1);
> +       PARSE_GRF_REG(con2);
> +       PARSE_GRF_REG(status0);
> +       PARSE_GRF_REG(status1);
> +       return ret;
> +}
> +
> +static int rockchip_typec_phy_probe(struct platform_device *pdev)
> +{
> +       struct device *dev = &pdev->dev;
> +       struct rockchip_typec_phy *tcphy;
> +       struct resource *res;
> +       struct phy_provider *phy_provider;
> +
> +       tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
> +       if (!tcphy)
> +               return -ENOMEM;
> +
> +       tcphy->dev = dev;
> +       platform_set_drvdata(pdev, tcphy);
> +
> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> +       tcphy->base = devm_ioremap_resource(dev, res);
> +       if (IS_ERR(tcphy->base)) {
> +               dev_err(dev, "failed to remap phy regs\n");
> +               return PTR_ERR(tcphy->base);
> +       }
> +       tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node,
> +                                                       "rockchip,grf");
> +       if (IS_ERR(tcphy->grf_regs)) {
> +               dev_err(dev, "%s: could not find grf dt node\n", __func__);
> +               return PTR_ERR(tcphy->grf_regs);
> +       }
> +
> +       tcphy->clk_core = of_clk_get_by_name(dev->of_node, "tcpdcore");
> +       if (IS_ERR(tcphy->clk_core)) {
> +               dev_err(dev, "%s: could not get uphy core clock\n", __func__);

nit: No real need for __func__.  That's useful to add in when you
don't have a "dev" pointer and need a "pr_err" to show something that
will help the user find the right line of code.

> +               tcphy->clk_core = NULL;

So is tcpdcore optional or required?  Bindings doc says "required" and
the "dev_err" above implies required.  ...but then you don't return an
error code.  That makes it optional.  ...but then you use it
unconditional elsewhere in this file.  That makes it required.

Summary: return an error here, don't just set to NULL.

> +       }
> +
> +       tcphy->clk_ref = of_clk_get_by_name(dev->of_node, "tcpdphy_ref");
> +       if (IS_ERR(tcphy->clk_core)) {
> +               dev_err(dev, "%s: could not get uphy ref clock\n", __func__);
> +               tcphy->clk_core = NULL;

"if" test and NULL assignment are for wrong variables.

> +       }
> +
> +       tcphy->phy_rst = devm_reset_control_get(dev, "tcphy_rst");
> +       if (IS_ERR(tcphy->phy_rst)) {
> +               dev_err(dev, "no phy_rst reset control found\n");
> +               return PTR_ERR(tcphy->phy_rst);
> +       }
> +
> +       tcphy->pipe_rst = devm_reset_control_get(dev, "tcphy_pipe_rst");
> +       if (IS_ERR(tcphy->pipe_rst)) {
> +               dev_err(dev, "no pipe_rst reset control found\n");
> +               return PTR_ERR(tcphy->pipe_rst);
> +       }
> +
> +       tcphy->uphy_rst = devm_reset_control_get(dev, "uphy_tcphy_rst");
> +       if (IS_ERR(tcphy->uphy_rst)) {
> +               dev_err(dev, "no uphy_rst reset control found\n");
> +               return PTR_ERR(tcphy->uphy_rst);
> +       }
> +
> +       tcphy_parse_reg(tcphy, dev);
> +       tcphy->mode = MODE_DISCONNECT;
> +
> +       tcphy->phy = devm_phy_create(dev, NULL, NULL);
> +
> +       phy_set_drvdata(tcphy->phy, tcphy);
> +
> +       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
> +
> +       /* register notifier for PD event */
> +       ATOMIC_INIT_NOTIFIER_HEAD(&tcphy->notifier);
> +       tcphy->event_nb.notifier_call = tcphy_pd_event;
> +       INIT_DELAYED_WORK(&tcphy->event_wq, tcphy_event_wq);
> +       tcphy_register_notifier(tcphy->phy, &tcphy->event_nb);
> +
> +       return PTR_ERR_OR_ZERO(phy_provider);
> +}
> +
> +static int rockchip_typec_phy_remove(struct platform_device *pdev)
> +{
> +       return 0;
> +}

I believe that if you've got an empty remove function you can just remove it.

...but doesn't remove need to call tcphy_unregister_notifier?


> +
> +static const struct of_device_id rockchip_typec_phy_dt_ids[] = {
> +       { .compatible = "rockchip,rk3399-typec-phy", },
> +       {}
> +};
> +
> +MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids);
> +
> +static struct platform_driver rockchip_typec_phy_driver = {
> +       .probe          = rockchip_typec_phy_probe,
> +       .remove         = rockchip_typec_phy_remove,
> +       .driver         = {
> +               .name   = "rockchip-typec-phy",
> +               .of_match_table = rockchip_typec_phy_dt_ids,
> +       },
> +};
> +
> +module_platform_driver(rockchip_typec_phy_driver);
> +
> +MODULE_AUTHOR("Kever Yang<kever.yang at rock-chips.com>");

nit: space before "<"

> +MODULE_AUTHOR("Chris Zhong<zyw at rock-chips.com>");
> +MODULE_DESCRIPTION("Rockchip USB TYPE-C PHY driver");
> +MODULE_LICENSE("GPL v2");
> --
> 2.6.3
>


From zyw at rock-chips.com  Tue May 31 17:35:09 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Wed, 1 Jun 2016 08:35:09 +0800
Subject: [PATCH 1/6] phy: Add USB Type-C PHY driver for rk3399
In-Reply-To: <CAD=FV=V1qX_YTTygsz=v+p6BdG8VZcu8np2nDvm1NiJHDnf==g@mail.gmail.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
 <1464328939-8073-2-git-send-email-zyw@rock-chips.com>
 <CAD=FV=V1qX_YTTygsz=v+p6BdG8VZcu8np2nDvm1NiJHDnf==g@mail.gmail.com>
Message-ID: <574E2DBD.8000900@rock-chips.com>

Hi Doug

Thanks for your review, I will modified them in next version(v1)
and with Guenter Roeck's comments in:
https://chromium-review.googlesource.com/#/c/348154/



On 06/01/2016 05:35 AM, Doug Anderson wrote:
> Chris,
>
> On Thu, May 26, 2016 at 11:02 PM, Chris Zhong <zyw at rock-chips.com> wrote:
>> Add a PHY provider driver for the rk3399 SoC Type-c PHY. The USB
>> Type-C PHY is designed to support the USB3 and DP applications. The
>> PHY basically has two main components: USB3 and DisplyPort. USB3
>> operates in SuperSpeed mode and the DP can operate at RBR, HBR and
>> HBR2 data rates.
>>
>> Signed-off-by: Chris Zhong <zyw at rock-chips.com>
>> ---
>>
>>   drivers/phy/Kconfig              |   7 +
>>   drivers/phy/Makefile             |   1 +
>>   drivers/phy/phy-rockchip-typec.c | 823 +++++++++++++++++++++++++++++++++++++++
>>   3 files changed, 831 insertions(+)
> This is a bit of a superficial review.  Hopefully we can find someone
> to do something more thorough.I
>
>
>>   create mode 100644 drivers/phy/phy-rockchip-typec.c
>>
>> diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig
>> index 26566db..dc388a3d 100644
>> --- a/drivers/phy/Kconfig
>> +++ b/drivers/phy/Kconfig
>> @@ -351,6 +351,13 @@ config PHY_ROCKCHIP_DP
>>          help
>>            Enable this to support the Rockchip Display Port PHY.
>>
>> +config PHY_ROCKCHIP_TYPEC
>> +       tristate "Rockchip TYPEC PHY Driver"
>> +       depends on ARCH_ROCKCHIP && OF
>> +       select GENERIC_PHY
>> +       help
>> +         Enable this to support the Rockchip USB TYPEC PHY.
>> +
>>   config PHY_ST_SPEAR1310_MIPHY
>>          tristate "ST SPEAR1310-MIPHY driver"
>>          select GENERIC_PHY
>> diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile
>> index 24596a9..91fa413 100644
>> --- a/drivers/phy/Makefile
>> +++ b/drivers/phy/Makefile
>> @@ -39,6 +39,7 @@ obj-$(CONFIG_PHY_QCOM_APQ8064_SATA)   += phy-qcom-apq8064-sata.o
>>   obj-$(CONFIG_PHY_ROCKCHIP_USB) += phy-rockchip-usb.o
>>   obj-$(CONFIG_PHY_ROCKCHIP_EMMC) += phy-rockchip-emmc.o
>>   obj-$(CONFIG_PHY_ROCKCHIP_DP)          += phy-rockchip-dp.o
>> +obj-$(CONFIG_PHY_ROCKCHIP_TYPEC) += phy-rockchip-typec.o
>>   obj-$(CONFIG_PHY_QCOM_IPQ806X_SATA)    += phy-qcom-ipq806x-sata.o
>>   obj-$(CONFIG_PHY_ST_SPEAR1310_MIPHY)   += phy-spear1310-miphy.o
>>   obj-$(CONFIG_PHY_ST_SPEAR1340_MIPHY)   += phy-spear1340-miphy.o
>> diff --git a/drivers/phy/phy-rockchip-typec.c b/drivers/phy/phy-rockchip-typec.c
>> new file mode 100644
>> index 0000000..6609cfb
>> --- /dev/null
>> +++ b/drivers/phy/phy-rockchip-typec.c
>> @@ -0,0 +1,823 @@
>> +/*
>> + * Rockchip usb3 PHY driver
>> + *
>> + * Copyright (C) 2016 Kever Yang <kever.yang at rock-chips.com>
>> + *                    Chris Zhong <zyw at rock-chips.com>
>> + * Copyright (C) 2016 ROCKCHIP, Inc.
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#include <linux/clk.h>
>> +#include <linux/clk-provider.h>
>> +#include <linux/io.h>
>> +#include <linux/iopoll.h>p
>> +#include <linux/kernel.h>
>> +#include <linux/module.h>
>> +#include <linux/mutex.h>
>> +#include <linux/of.h>
>> +#include <linux/of_address.h>
>> +#include <linux/of_platform.h>
>> +#include <linux/phy/phy.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/reset.h>
>> +#include <linux/regmap.h>
>> +#include <linux/mfd/syscon.h>
>> +#include <linux/delay.h>
>> +#include <linux/phy/phy-rockchip-typec.h>
>> +
>> +#define ADDR_ADJ                       2
>> +#define CMN_SSM_BANDGAP                        (0x21 << ADDR_ADJ)
>> +#define CMN_SSM_BIAS                   (0x22 << ADDR_ADJ)
>> +#define CMN_PLLSM0_PLLEN               (0x29 << ADDR_ADJ)
>> +#define CMN_PLLSM0_PLLPRE              (0x2a << ADDR_ADJ)
>> +#define CMN_PLLSM0_PLLVREF             (0x2b << ADDR_ADJ)
>> +#define CMN_PLLSM0_PLLLOCK             (0x2c << ADDR_ADJ)
>> +#define CMN_PLLSM1_PLLEN               (0x31 << ADDR_ADJ)
>> +#define CMN_PLLSM1_PLLPRE              (0x32 << ADDR_ADJ)
>> +#define CMN_PLLSM1_PLLVREF             (0x33 << ADDR_ADJ)
>> +#define CMN_PLLSM1_PLLLOCK             (0x34 << ADDR_ADJ)
>> +#define CMN_PLLSM1_USER_DEF_CTRL       (0x37 << ADDR_ADJ)
>> +#define CMN_ICAL_OVRD                  (0xc1 << ADDR_ADJ)
>> +#define CMN_PLL0_VCOCAL_OVRD           (0x83 << ADDR_ADJ)
>> +#define CMN_PLL0_VCOCAL_INIT           (0x84 << ADDR_ADJ)
>> +#define CMN_PLL0_VCOCAL_ITER           (0x85 << ADDR_ADJ)
>> +#define CMN_PLL0_LOCK_REFCNT_START     (0x90 << ADDR_ADJ)
>> +#define CMN_PLL0_LOCK_PLLCNT_START     (0x92 << ADDR_ADJ)
>> +#define CMN_PLL0_LOCK_PLLCNT_THR       (0x93 << ADDR_ADJ)
>> +#define CMN_PLL0_INTDIV                        (0x94 << ADDR_ADJ)
>> +#define CMN_PLL0_FRACDIV               (0x95 << ADDR_ADJ)
>> +#define CMN_PLL0_HIGH_THR              (0x96 << ADDR_ADJ)
>> +#define CMN_PLL0_DSM_DIAG              (0x97 << ADDR_ADJ)
>> +#define CMN_PLL0_SS_CTRL1              (0x98 << ADDR_ADJ)
>> +#define CMN_PLL0_SS_CTRL2              (0x99 << ADDR_ADJ)
>> +#define CMN_PLL1_VCOCAL_START          (0xa1 << ADDR_ADJ)
>> +#define CMN_PLL1_VCOCAL_OVRD           (0xa3 << ADDR_ADJ)
>> +#define CMN_PLL1_VCOCAL_INIT           (0xa4 << ADDR_ADJ)
>> +#define CMN_PLL1_VCOCAL_ITER           (0xa5 << ADDR_ADJ)
>> +#define CMN_PLL1_LOCK_REFCNT_START     (0xb0 << ADDR_ADJ)
>> +#define CMN_PLL1_LOCK_PLLCNT_START     (0xb2 << ADDR_ADJ)
>> +#define CMN_PLL1_LOCK_PLLCNT_THR       (0xb3 << ADDR_ADJ)
>> +#define CMN_PLL1_INTDIV                        (0xb4 << ADDR_ADJ)
>> +#define CMN_PLL1_FRACDIV               (0xb5 << ADDR_ADJ)
>> +#define CMN_PLL1_HIGH_THR              (0xb6 << ADDR_ADJ)
>> +#define CMN_PLL1_DSM_DIAG              (0xb7 << ADDR_ADJ)
>> +#define CMN_PLL1_SS_CTRL1              (0xb8 << ADDR_ADJ)
>> +#define CMN_PLL1_SS_CTRL2              (0xb9 << ADDR_ADJ)
>> +#define CMN_RXCAL_OVRD                 (0xd1 << ADDR_ADJ)
>> +#define CMN_TXPUCAL_CTRL               (0xe0 << ADDR_ADJ)
>> +#define CMN_TXPUCAL_OVRD               (0xe1 << ADDR_ADJ)
>> +#define CMN_TXPDCAL_OVRD               (0xf1 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL0_FBH_OVRD         (0x1c0 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL0_FBL_OVRD         (0x1c1 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL0_OVRD             (0x1c2 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL0_V2I_TUNE         (0x1c5 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL0_CP_TUNE          (0x1c6 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL0_LF_PROG          (0x1c7 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL1_FBH_OVRD         (0x1d0 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL1_FBL_OVRD         (0x1d1 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL1_OVRD             (0x1d2 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL1_V2I_TUNE         (0x1d5 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL1_CP_TUNE          (0x1d6 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL1_LF_PROG          (0x1d7 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL1_PTATIS_TUNE1     (0x1d8 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL1_PTATIS_TUNE2     (0x1d9 << ADDR_ADJ)
>> +#define CMN_DIAG_PLL1_INCLK_CTRL       (0x1da << ADDR_ADJ)
>> +#define CMN_DIAG_HSCLK_SEL             (0x1e0 << ADDR_ADJ)
>> +
>> +#define XCVR_PSM_RCTRL(n)              ((0x4001 | (n << 9)) << ADDR_ADJ)
>> +#define XCVR_PSM_CAL_TMR(n)            ((0x4002 | (n << 9)) << ADDR_ADJ)
>> +#define XCVR_PSM_A0IN_TMR(n)           ((0x4003 | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_CAL_SCLR_MULT(n)       ((0x4047 | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_CPOST_MULT_00(n)       ((0x404c | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_CPOST_MULT_01(n)       ((0x404d | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_CPOST_MULT_10(n)       ((0x404e | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_CPOST_MULT_11(n)       ((0x404f | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_MGNFS_MULT_000(n)      ((0x4050 | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_MGNFS_MULT_001(n)      ((0x4051 | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_MGNFS_MULT_010(n)      ((0x4052 | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_MGNFS_MULT_011(n)      ((0x4053 | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_MGNFS_MULT_100(n)      ((0x4054 | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_MGNFS_MULT_101(n)      ((0x4055 | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_MGNFS_MULT_110(n)      ((0x4056 | (n << 9)) << ADDR_ADJ)
>> +#define TX_TXCC_MGNFS_MULT_111(n)      ((0x4057 | (n << 9)) << ADDR_ADJ)
>> +#define XCVR_DIAG_PLLDRC_CTRL(n)       ((0x40e0 | (n << 9)) << ADDR_ADJ)
>> +#define XCVR_DIAG_BIDI_CTRL(n)         ((0x40e8 | (n << 9)) << ADDR_ADJ)
>> +#define XCVR_DIAG_LANE_FCM_EN_MGN(n)   ((0x40f2 | (n << 9)) << ADDR_ADJ)
>> +#define TX_PSC_A0(n)                   ((0x4100 | (n << 9)) << ADDR_ADJ)
>> +#define TX_PSC_A1(n)                   ((0x4101 | (n << 9)) << ADDR_ADJ)
>> +#define TX_PSC_A2(n)                   ((0x4102 | (n << 9)) << ADDR_ADJ)
>> +#define TX_PSC_A3(n)                   ((0x4103 | (n << 9)) << ADDR_ADJ)
>> +#define TX_RCVDET_CTRL(n)              ((0x4120 | (n << 9)) << ADDR_ADJ)
>> +#define TX_RCVDET_EN_TMR(n)            ((0x4122 | (n << 9)) << ADDR_ADJ)
>> +#define TX_RCVDET_ST_TMR(n)            ((0x4123 | (n << 9)) << ADDR_ADJ)
>> +#define TX_DIAG_TX_DRV(n)              ((0x41e1 | (n << 9)) << ADDR_ADJ)
>> +#define TX_DIAG_BGREF_PREDRV_DELAY     (0x41e7 << ADDR_ADJ)
>> +#define TX_ANA_CTRL_REG_1              (0x5020 << ADDR_ADJ)
>> +#define TX_ANA_CTRL_REG_2              (0x5021 << ADDR_ADJ)
>> +#define TXDA_COEFF_CALC_CTRL           (0x5022 << ADDR_ADJ)
>> +#define TX_DIG_CTRL_REG_2              (0x5024 << ADDR_ADJ)
>> +#define TXDA_CYA_AUXDA_CYA             (0x5025 << ADDR_ADJ)
>> +#define TX_ANA_CTRL_REG_3              (0x5026 << ADDR_ADJ)
>> +#define TX_ANA_CTRL_REG_4              (0x5027 << ADDR_ADJ)
>> +#define TX_ANA_CTRL_REG_5              (0x5029 << ADDR_ADJ)
>> +
>> +#define RX_PSC_A0(n)                   ((0x8000 | (n << 9)) << ADDR_ADJ)
>> +#define RX_PSC_A1(n)                   ((0x8001 | (n << 9)) << ADDR_ADJ)
>> +#define RX_PSC_A2(n)                   ((0x8002 | (n << 9)) << ADDR_ADJ)
>> +#define RX_PSC_A3(n)                   ((0x8003 | (n << 9)) << ADDR_ADJ)
>> +#define RX_PSC_CAL(n)                  ((0x8006 | (n << 9)) << ADDR_ADJ)
>> +#define RX_PSC_RDY(n)                  ((0x8007 | (n << 9)) << ADDR_ADJ)
>> +#define RX_IQPI_ILL_CAL_OVRD           (0x8023 << ADDR_ADJ)
>> +#define RX_EPI_ILL_CAL_OVRD            (0x8033 << ADDR_ADJ)
>> +#define RX_SDCAL0_OVRD                 (0x8041 << ADDR_ADJ)
>> +#define RX_SDCAL1_OVRD                 (0x8049 << ADDR_ADJ)
>> +#define RX_SLC_INIT                    (0x806d << ADDR_ADJ)
>> +#define RX_SLC_RUN                     (0x806e << ADDR_ADJ)
>> +#define RX_CDRLF_CNFG2                 (0x8081 << ADDR_ADJ)
>> +#define RX_SIGDET_HL_FILT_TMR(n)       ((0x8090 | (n << 9)) << ADDR_ADJ)
>> +#define RX_SLC_IOP0_OVRD               (0x8101 << ADDR_ADJ)
>> +#define RX_SLC_IOP1_OVRD               (0x8105 << ADDR_ADJ)
>> +#define RX_SLC_QOP0_OVRD               (0x8109 << ADDR_ADJ)
>> +#define RX_SLC_QOP1_OVRD               (0x810d << ADDR_ADJ)
>> +#define RX_SLC_EOP0_OVRD               (0x8111 << ADDR_ADJ)
>> +#define RX_SLC_EOP1_OVRD               (0x8115 << ADDR_ADJ)
>> +#define RX_SLC_ION0_OVRD               (0x8119 << ADDR_ADJ)
>> +#define RX_SLC_ION1_OVRD               (0x811d << ADDR_ADJ)
>> +#define RX_SLC_QON0_OVRD               (0x8121 << ADDR_ADJ)
>> +#define RX_SLC_QON1_OVRD               (0x8125 << ADDR_ADJ)
>> +#define RX_SLC_EON0_OVRD               (0x8129 << ADDR_ADJ)
>> +#define RX_SLC_EON1_OVRD               (0x812d << ADDR_ADJ)
>> +#define RX_SLC_IEP0_OVRD               (0x8131 << ADDR_ADJ)
>> +#define RX_SLC_IEP1_OVRD               (0x8135 << ADDR_ADJ)
>> +#define RX_SLC_QEP0_OVRD               (0x8139 << ADDR_ADJ)
>> +#define RX_SLC_QEP1_OVRD               (0x813d << ADDR_ADJ)
>> +#define RX_SLC_EEP0_OVRD               (0x8141 << ADDR_ADJ)
>> +#define RX_SLC_EEP1_OVRD               (0x8145 << ADDR_ADJ)
>> +#define RX_SLC_IEN0_OVRD               (0x8149 << ADDR_ADJ)
>> +#define RX_SLC_IEN1_OVRD               (0x814d << ADDR_ADJ)
>> +#define RX_SLC_QEN0_OVRD               (0x8151 << ADDR_ADJ)
>> +#define RX_SLC_QEN1_OVRD               (0x8155 << ADDR_ADJ)
>> +#define RX_SLC_EEN0_OVRD               (0x8159 << ADDR_ADJ)
>> +#define RX_SLC_EEN1_OVRD               (0x815d << ADDR_ADJ)
>> +#define RX_DIAG_SIGDET_TUNE(n)         ((0x81dc | (n << 9)) << ADDR_ADJ)
>> +#define RX_DIAG_SC2C_DELAY             (0x81e1 << ADDR_ADJ)
>> +
>> +#define PMA_LANE_CFG                   (0xc000 << ADDR_ADJ)
>> +#define PIPE_CMN_CTRL1                 (0xc001 << ADDR_ADJ)
>> +#define PIPE_CMN_CTRL2                 (0xc002 << ADDR_ADJ)
>> +#define PIPE_COM_LOCK_CFG1             (0xc003 << ADDR_ADJ)
>> +#define PIPE_COM_LOCK_CFG2             (0xc004 << ADDR_ADJ)
>> +#define PIPE_RCV_DET_INH               (0xc005 << ADDR_ADJ)
>> +#define DP_MODE_CTL                    (0xc008 << ADDR_ADJ)
>> +#define DP_CLK_CTL                     (0xc009 << ADDR_ADJ)
>> +#define STS                            (0xc00F << ADDR_ADJ)
>> +#define PHY_ISO_CMN_CTRL               (0xc010 << ADDR_ADJ)
>> +#define PHY_DP_TX_CTL                  (0xc408 << ADDR_ADJ)
>> +#define PMA_CMN_CTRL1                  (0xc800 << ADDR_ADJ)
>> +#define PHY_PMA_ISO_CMN_CTRL           (0xc810 << ADDR_ADJ)
>> +#define PHY_ISOLATION_CTRL             (0xc81f << ADDR_ADJ)
>> +#define PHY_PMA_ISO_XCVR_CTRL(n)       ((0xcc11 | (n << 6)) << ADDR_ADJ)
>> +#define PHY_PMA_ISO_LINK_MODE(n)       ((0xcc12 | (n << 6)) << ADDR_ADJ)
>> +#define PHY_PMA_ISO_PWRST_CTRL(n)      ((0xcc13 | (n << 6)) << ADDR_ADJ)
>> +#define PHY_PMA_ISO_TX_DATA_LO(n)      ((0xcc14 | (n << 6)) << ADDR_ADJ)
>> +#define PHY_PMA_ISO_TX_DATA_HI(n)      ((0xcc15 | (n << 6)) << ADDR_ADJ)
>> +#define PHY_PMA_ISO_RX_DATA_LO(n)      ((0xcc16 | (n << 6)) << ADDR_ADJ)
>> +#define PHY_PMA_ISO_RX_DATA_HI(n)      ((0xcc17 | (n << 6)) << ADDR_ADJ)
>> +#define TX_BIST_CTRL(n)                        ((0x4140 | (n << 9)) << ADDR_ADJ)
>> +#define TX_BIST_UDDWR(n)               ((0x4141 | (n << 9)) << ADDR_ADJ)
>> +
>> +#define GRF_SOC_CON26                  0x6268
>> +#define UPHY_DP_SEL                    BIT(3)
>> +#define UPHY_DP_SEL_MASK               BIT(19)
>> +#define DPTX_HDP_SEL                   (3 << 12)
>> +#define DPTX_HDP_SEL_MASK              (3 << 28)
>> +
>> +#define PHY_MODE_SET_TIMEOUT           1000000
>> +
>> +#define        MODE_DISCONNECT                 1
>> +#define        MODE_UFP                        2
>> +#define        MODE_DFP_USBONLY                3
>> +#define        MODE_DFP_DPONLY                 4
>> +#define        MODE_DFP_USB3DP                 5
>> +#define        MODE_DFP_USB2DP                 6
>> +
>> +#define PARSE_GRF_REG(TYPE) { \
>> +       if (of_find_property(np, "rockchip,usb3phy_"#TYPE, &len)) { \
>> +               len /= sizeof(u32);\
>> +               ret = of_property_read_u32_array(np, "rockchip,usb3phy_" #TYPE,\
>> +                                                array, len); \
>> +               exregs->usb3phy_##TYPE = array[0]; \
>> +               exregs->usb3phy_##TYPE##_shift = array[1]; \
>> +               exregs->usb3phy_##TYPE##_mask = array[2]; \
>> +               pr_info("%s property found %s, %x, %d, %d\n", __func__, \
>> +                       "rockchip,usb3phy_"#TYPE, \
>> +                       array[0], array[1], array[2]); \
>> +       } else { \
>> +               pr_info("%s property not found %s\n", __func__, \
>> +                       "rockchip,usb3phy_" #TYPE); \
>> +       } \
>> +}
>> +
>> +struct rockchip_typec_phy *rockchip_tcphy;
> Unused global?
>
>> +
>> +static void tcphy_cfg_24m(struct rockchip_typec_phy *tcphy,
>> +                         unsigned int num_lanes)
>> +{
>> +       unsigned int i;()?
>> +
>> +       writel(0x830, tcphy->base + PMA_CMN_CTRL1);
>> +       for (i = 0; i < num_lanes; i++) {
>> +               writel(0x90, tcphy->base + XCVR_DIAG_LANE_FCM_EN_MGN(i));
>> +               writel(0x960, tcphy->base + TX_RCVDET_EN_TMR(i));
>> +               writel(0x30, tcphy->base + TX_RCVDET_ST_TMR(i));
> Would it be too much to ask to get more details about all these magic values?
>
>> +       }
>> +}
>> +
>> +static void tcphy_cfg_usb_pll(struct rockchip_typec_phy *tcphy)
>> +{
>> +       unsigned int rdata;
>> +
>> +       rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
>> +       writel(rdata & 0xfffc, tcphy->base + CMN_DIAG_HSCLK_SEL);
>> +       writel(0xf0, tcphy->base + CMN_PLL0_VCOCAL_INIT);
>> +       writel(0x18, tcphy->base + CMN_PLL0_VCOCAL_ITER);
>> +       writel(0xd0, tcphy->base + CMN_PLL0_INTDIV);
>> +       writel(0x4a4a, tcphy->base + CMN_PLL0_FRACDIV);
>> +       writel(0x34, tcphy->base + CMN_PLL0_HIGH_THR);
>> +       writel(0x1ee, tcphy->base + CMN_PLL0_SS_CTRL1);
>> +       writel(0x7f03, tcphy->base + CMN_PLL0_SS_CTRL2);
>> +       writel(0x20, tcphy->base + CMN_PLL0_DSM_DIAG);
>> +       writel(0, tcphy->base + CMN_DIAG_PLL0_OVRD);
>> +       writel(0, tcphy->base + CMN_DIAG_PLL0_FBH_OVRD);
>> +       writel(0, tcphy->base + CMN_DIAG_PLL0_FBL_OVRD);
>> +       writel(0x7, tcphy->base + CMN_DIAG_PLL0_V2I_TUNE);
>> +       writel(0x45, tcphy->base + CMN_DIAG_PLL0_CP_TUNE);
>> +       writel(0x8, tcphy->base + CMN_DIAG_PLL0_LF_PROG);
>> +}
>> +
>> +static void tcphy_cfg_dp_pll(struct rockchip_typec_phy *tcphy)
>> +{
>> +       unsigned int rdata;
>> +
>> +       writel(0x2405, tcphy->base + DP_CLK_CTL);
>> +
>> +       rdata = readl(tcphy->base + CMN_DIAG_HSCLK_SEL);
>> +       rdata = (rdata & 0xffcf) | 0x30;
>> +       writel(rdata, tcphy->base + CMN_DIAG_HSCLK_SEL);
>> +       writel(0xf0, tcphy->base + CMN_PLL1_VCOCAL_INIT);
>> +       writel(0x18, tcphy->base + CMN_PLL1_VCOCAL_ITER);
>> +       writel(0x30b9, tcphy->base + CMN_PLL1_VCOCAL_START);
>> +       writel(0x21c, tcphy->base + CMN_PLL1_INTDIV);
>> +       writel(0, tcphy->base + CMN_PLL1_FRACDIV);
>> +       writel(0x5, tcphy->base + CMN_PLL1_HIGH_THR);
>> +       writel(0x35, tcphy->base + CMN_PLL1_SS_CTRL1);
>> +       writel(0x7f1e, tcphy->base + CMN_PLL1_SS_CTRL2);
>> +       writel(0x20, tcphy->base + CMN_PLL1_DSM_DIAG);
>> +       writel(0, tcphy->base + CMN_PLLSM1_USER_DEF_CTRL);
>> +       writel(0, tcphy->base + CMN_DIAG_PLL1_OVRD);
>> +       writel(0, tcphy->base + CMN_DIAG_PLL1_FBH_OVRD);
>> +       writel(0, tcphy->base + CMN_DIAG_PLL1_FBL_OVRD);
>> +       writel(0x6, tcphy->base + CMN_DIAG_PLL1_V2I_TUNE);
>> +       writel(0x45, tcphy->base + CMN_DIAG_PLL1_CP_TUNE);
>> +       writel(0x8, tcphy->base + CMN_DIAG_PLL1_LF_PROG);
>> +       writel(0x100, tcphy->base + CMN_DIAG_PLL1_PTATIS_TUNE1);
>> +       writel(0x7, tcphy->base + CMN_DIAG_PLL1_PTATIS_TUNE2);
>> +       writel(0x4, tcphy->base + CMN_DIAG_PLL1_INCLK_CTRL);
>> +}
>> +
>> +static void tcphy_tx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
>> +                                 unsigned int lane)
>> +{
>> +       writel(0x7799, tcphy->base + TX_PSC_A0(lane));
>> +       writel(0x7798, tcphy->base + TX_PSC_A1(lane));
>> +       writel(0x5098, tcphy->base + TX_PSC_A2(lane));
>> +       writel(0x5098, tcphy->base + TX_PSC_A3(lane));
>> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
>> +       writel(0xbf, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
>> +}
>> +
>> +static void tcphy_rx_usb_cfg_lane(struct rockchip_typec_phy *tcphy,
>> +                                 unsigned int lane)
>> +{
>> +       writel(0xa6fd, tcphy->base + RX_PSC_A0(lane));
>> +       writel(0xa6fd, tcphy->base + RX_PSC_A1(lane));
>> +       writel(0xa410, tcphy->base + RX_PSC_A2(lane));
>> +       writel(0x2410, tcphy->base + RX_PSC_A3(lane));
>> +       writel(0x23ff, tcphy->base + RX_PSC_CAL(lane));
>> +       writel(0x13, tcphy->base + RX_SIGDET_HL_FILT_TMR(lane));
>> +       writel(0x1004, tcphy->base + RX_DIAG_SIGDET_TUNE(lane));
>> +       writel(0x2010, tcphy->base + RX_PSC_RDY(lane));
>> +       writel(0xfb, tcphy->base + XCVR_DIAG_BIDI_CTRL(lane));
>> +}
>> +
>> +static void tcphy_dp_cfg_lane(struct rockchip_typec_phy *tcphy,
>> +                             unsigned int lane)
>> +{
>> +       unsigned int rdata;
>> +
>> +       writel(0xbefc, tcphy->base + XCVR_PSM_RCTRL(lane));
>> +       writel(0x6799, tcphy->base + TX_PSC_A0(lane));
>> +       writel(0x6798, tcphy->base + TX_PSC_A1(lane));
>> +       writel(0x98, tcphy->base + TX_PSC_A2(lane));
>> +       writel(0x98, tcphy->base + TX_PSC_A3(lane));
>> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_000(lane));
>> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_001(lane));
>> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_010(lane));
>> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_011(lane));
>> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_100(lane));
>> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_101(lane));
>> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_110(lane));
>> +       writel(0, tcphy->base + TX_TXCC_MGNFS_MULT_111(lane));
>> +
>> +       writel(0, tcphy->base + TX_TXCC_CPOST_MULT_10(lane));
>> +       writel(0, tcphy->base + TX_TXCC_CPOST_MULT_01(lane));
>> +       writel(0, tcphy->base + TX_TXCC_CPOST_MULT_00(lane));
>> +       writel(0, tcphy->base + TX_TXCC_CPOST_MULT_11(lane));
>> +
>> +       writel(0x128, tcphy->base + TX_TXCC_CAL_SCLR_MULT(lane));
>> +       writel(0x700, tcphy->base + TX_DIAG_TX_DRV(lane));
>> +
>> +       rdata = readl(tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
>> +       rdata = (rdata & 0x8fff) | 0x6000;
>> +       writel(rdata, tcphy->base + XCVR_DIAG_PLLDRC_CTRL(lane));
>> +}
>> +
>> +static void tcphy_cfg_pin_assign(struct rockchip_typec_phy *tcphy)
>> +{
>> +       switch (tcphy->map) {
>> +       case PIN_MAP_A:
>> +               writel(0x19d5, tcphy->base + PMA_LANE_CFG);
>> +               break;
>> +       case PIN_MAP_B:
>> +               writel(0x1500, tcphy->base + PMA_LANE_CFG);
>> +               break;
>> +       case PIN_MAP_C:
>> +       case PIN_MAP_E:
>> +               writel(0x51d9, tcphy->base + PMA_LANE_CFG);
>> +               break;
>> +       case PIN_MAP_D:
>> +       case PIN_MAP_F:
>> +               writel(0x5100, tcphy->base + PMA_LANE_CFG);
>> +               break;
>> +       };
>> +}
>> +
>> +static void tcphy_cfg_lanes(struct rockchip_typec_phy *tcphy,
>> +                           unsigned int link_cfg)
>> +{
>> +       unsigned int i;
>> +
>> +       /* PMA lane configuration DP or USB3 */
>> +       for (i = 0; i < 4; i++) {
>> +               if ((link_cfg >> i) & 0x1) {
>> +                       tcphy_dp_cfg_lane(tcphy, i);
>> +               } else {
>> +                       /*
>> +                        * lan0 TX and lan1 RX for USB3 Normal direction
>> +                        * lan3 TX and lan2 RX for USB3 Flip direction
>> +                        */
>> +                       if ((i == 0) | (i == 3))
>> +                               tcphy_tx_usb_cfg_lane(tcphy, i);
>> +                       else
>> +                               tcphy_rx_usb_cfg_lane(tcphy, i);
>> +               }
>> +       }
>> +}
>> +
>> +static void tcphy_cfg_flip_set(struct rockchip_typec_phy *tcphy)
>> +{
>> +       regmap_write(tcphy->grf_regs,
>> +                    tcphy->exregs.usb3phy_con0,
>> +                    tcphy->flip | BIT(16));
>> +
>> +       tcphy_cfg_24m(tcphy, 0x4);
>> +
>> +       if (tcphy->mode == MODE_UFP ||
>> +           tcphy->mode == MODE_DFP_USBONLY ||
>> +           tcphy->mode == MODE_DFP_USB3DP)
>> +               tcphy_cfg_usb_pll(tcphy);
>> +
>> +       if (tcphy->mode == MODE_DFP_DPONLY ||
>> +           tcphy->mode == MODE_DFP_USB2DP ||
>> +           tcphy->mode == MODE_DFP_USB3DP)
>> +               tcphy_cfg_dp_pll(tcphy);
>> +
>> +       if (tcphy->mode == MODE_DFP_DPONLY || tcphy->mode == MODE_DFP_USB2DP)
>> +               tcphy_cfg_lanes(tcphy, 0xf);
>> +       else if (tcphy->flip)
>> +               tcphy_cfg_lanes(tcphy, 0x3);
>> +       else
>> +               tcphy_cfg_lanes(tcphy, 0xc);
>> +}
>> +
>> +static void tcphy_dp_aux_calibration(struct rockchip_typec_phy *tcphy)
>> +{
>> +       int rdata, rdata2, val;
>> +
>> +       rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
>> +       rdata2 = readl(tcphy->base + CMN_TXPUCAL_CTRL);
>> +
>> +       rdata = rdata & 0xdfff;
>> +       writel(rdata, tcphy->base + TX_ANA_CTRL_REG_1);
>> +
>> +       rdata = readl(tcphy->base + TX_DIG_CTRL_REG_2);
>> +       rdata = rdata & 0xffc0;
>> +       rdata2 = rdata2 & 0x3f;
>> +       rdata  = rdata | rdata2;
>> +       writel(rdata, tcphy->base + TX_DIG_CTRL_REG_2);
>> +       usleep_range(1000, 2000);
> nit: this is at init time and will be run once.  Power savings of
> trying to group wakeups will be minimal or none.  Last I looked
> usleep_range() nearly always takes the longer of the two times unless
> it happens to wake up anyway.  Make the range smaller and boot time
> will be 1ms faster.  Try usleep_range(1000, 1050).
>
>> +
>> +       rdata = readl(tcphy->base + TX_ANA_CTRL_REG_1);
>> +       rdata = rdata | 0x2000;
>> +       writel(rdata, tcphy->base + TX_ANA_CTRL_REG_1);
>> +
>> +       usleep_range(150, 200);
>> +
>> +       writel(0, tcphy->base + PHY_DP_TX_CTL);
>> +       writel(0x100, tcphy->base + TX_ANA_CTRL_REG_2);
>> +       writel(0x300, tcphy->base + TX_ANA_CTRL_REG_2);
>> +       writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
>> +       writel(0x2008, tcphy->base + TX_ANA_CTRL_REG_1);
>> +       writel(0x2018, tcphy->base + TX_ANA_CTRL_REG_1);
>> +       writel(0x30C, tcphy->base + TX_ANA_CTRL_REG_2);
>> +       writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
>> +       writel(0x1001, tcphy->base + TX_ANA_CTRL_REG_4);
>> +       writel(0x2098, tcphy->base + TX_ANA_CTRL_REG_1);
>> +       writel(0x2198, tcphy->base + TX_ANA_CTRL_REG_1);
>> +       writel(0x30d, tcphy->base + TX_ANA_CTRL_REG_2);
>> +       writel(0x30f, tcphy->base + TX_ANA_CTRL_REG_2);
>> +
>> +       if (tcphy->flip)
>> +               writel(0xa078, tcphy->base + TX_ANA_CTRL_REG_1);
>> +       else
>> +               writel(0xb078, tcphy->base + TX_ANA_CTRL_REG_1);
>> +
>> +       writel(0x303, tcphy->base + TX_ANA_CTRL_REG_2);
>> +       writel(0, tcphy->base + TX_ANA_CTRL_REG_3);
>> +       writel(0, tcphy->base + TX_ANA_CTRL_REG_4);
>> +       writel(0, tcphy->base + TX_ANA_CTRL_REG_5);
>> +       writel(4, tcphy->base + TXDA_COEFF_CALC_CTRL);
>> +       writel(0, tcphy->base + TXDA_CYA_AUXDA_CYA);
>> +
>> +       val = readl(tcphy->base + TX_DIG_CTRL_REG_2);
>> +       val |= BIT(15);
>> +       writel(val, tcphy->base + TX_DIG_CTRL_REG_2);
>> +}
>> +
>> +static void tcphy_dp_hpd(struct rockchip_typec_phy *tcphy,
>> +                        u8 mode)
>> +{
>> +       /* force hpd */
>> +       if (mode)
>> +               regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
>> +                            DPTX_HDP_SEL_MASK | DPTX_HDP_SEL);
>> +       else
>> +               regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
>> +                            DPTX_HDP_SEL_MASK);
>> +}
>> +
>> +static int tcphy_usb3_init(struct rockchip_typec_phy *tcphy)
>> +{
>> +       int timeout = 0;
>> +       int ret, val;
>> +
>> +       /*wait TCPHY for pipe ready */
>> +       while (1) {
>> +               ret = regmap_read(tcphy->grf_regs,
>> +                                 tcphy->exregs.usb3phy_status0, &val);
>> +               val >>= tcphy->exregs.usb3phy_status0_shift;
>> +               if ((val & 0x1) == 0)
>> +                       break;
>> +
>> +               timeout++;
>> +               if (timeout > 1000) {
>> +                       pr_warn("%s wait pipe ready timerout!\n", __func__);
>> +                       break;
>> +               }
>> +               usleep_range(10, 20);
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int tcphy_dp_init(struct rockchip_typec_phy *tcphy)
>> +{
>> +       int ret, val;
>> +
>> +       ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
>> +                                val, val & BIT(6), 1000, PHY_MODE_SET_TIMEOUT);
>> +       if (ret < 0) {
>> +               dev_err(tcphy->dev, "failed to wait TCPHY for DP ready\n");
>> +               return -EBUSY;
>> +       }
>> +
>> +       tcphy_dp_aux_calibration(tcphy);
>> +
>> +       if (tcphy->mode == MODE_DFP_USB3DP)
>> +               writel(0xc101, tcphy->base + DP_MODE_CTL);
>> +       else
>> +               writel(0x0101, tcphy->base + DP_MODE_CTL);
>> +
>> +       ret = readx_poll_timeout(readl, tcphy->base + DP_MODE_CTL,
>> +                                val, val & BIT(4), 1000, PHY_MODE_SET_TIMEOUT);
>> +       if (ret < 0) {
>> +               dev_err(tcphy->dev, "failed to wait TCPHY enter A0\n");
>> +               return -EBUSY;
>> +       }
>> +
>> +       return 0;
>> +}
>> +
>> +static int tcphy_phy_init(struct rockchip_typec_phy *tcphy)
>> +{
>> +       int ret;
>> +       int timeout = 0;
>> +
>> +       ret = clk_prepare_enable(tcphy->clk_core);
>> +       if (ret) {
>> +               dev_err(tcphy->dev, "Failed to prepare_enable core clock\n");
>> +               return ret;
>> +       }
>> +
>> +       ret = clk_prepare_enable(tcphy->clk_ref);
>> +       if (ret) {
>> +               dev_err(tcphy->dev, "Failed to prepare_enable ref clock\n");
>> +               return ret;
>> +       }
>> +
>> +       /* select external psm clock */
>> +       regmap_write(tcphy->grf_regs, tcphy->exregs.usb3phy_con2,
>> +                    BIT(14) | BIT(30));
>> +       regmap_write(tcphy->grf_regs, tcphy->exregs.usb3phy_con0, BIT(19));
>> +
>> +       reset_control_assert(tcphy->phy_rst);
>> +       reset_control_assert(tcphy->pipe_rst);
>> +       reset_control_assert(tcphy->uphy_rst);
>> +
>> +       if (tcphy->num == TYPEC_PHY0)
>> +               regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
>> +                            UPHY_DP_SEL_MASK);
>> +       else
>> +               regmap_write(tcphy->grf_regs, GRF_SOC_CON26,
>> +                            UPHY_DP_SEL_MASK | UPHY_DP_SEL);
>> +
>> +       reset_control_deassert(tcphy->uphy_rst);
>> +
>> +       tcphy_cfg_flip_set(tcphy);
>> +
>> +       tcphy_cfg_pin_assign(tcphy);
>> +
>> +       if (tcphy->mode == MODE_DFP_USB3DP)
>> +               writel(0xc104, tcphy->base + DP_MODE_CTL);
>> +       else if ((tcphy->mode == MODE_DFP_DPONLY) ||
>> +                (tcphy->mode == MODE_DFP_USB2DP))
>> +               writel(0x0104, tcphy->base + DP_MODE_CTL);
>> +
>> +       reset_control_deassert(tcphy->phy_rst);
>> +
>> +       while (!(readl(tcphy->base + PMA_CMN_CTRL1) & 1)) {
>> +               timeout++;
>> +               if (timeout > 1000)
>> +                       break;
>> +               usleep_range(10, 20);
>> +       }
>> +
>> +       reset_control_deassert(tcphy->pipe_rst);
>> +
>> +       return 0;
>> +}
>> +
>> +static int tcphy_phy_deinit(struct rockchip_typec_phy *tcphy)
>> +{
>> +       clk_disable_unprepare(tcphy->clk_core);
>> +       clk_disable_unprepare(tcphy->clk_ref);
>> +
>> +       return 0;
>> +}
>> +
>> +int tcphy_register_notifier(struct phy *_phy, struct notifier_block *nb)
> Is there a reason this isn't static?
>
>> +{
>> +       struct rockchip_typec_phy *tcphy = phy_get_drvdata(_phy);
>> +
>> +       return atomic_notifier_chain_register(&tcphy->notifier, nb);
>> +}
>> +
>> +void tcphy_unregister_notifier(struct phy *_phy,
>> +                              struct notifier_block *nb)
> Is there a reason this isn't static?
>
>> +{
>> +       struct rockchip_typec_phy *tcphy = phy_get_drvdata(_phy);
>> +
>> +       atomic_notifier_chain_unregister(&tcphy->notifier, nb);
>> +}
>> +
>> +void tcphy_notifier_call_chain(struct rockchip_typec_phy *x,
>> +                              unsigned long val, void *v)
>> +{
>> +       atomic_notifier_call_chain(&x->notifier, val, v);
>> +}
>> +EXPORT_SYMBOL_GPL(tcphy_notifier_call_chain);
>> +
>> +static int tcphy_pd_event(struct notifier_block *nb,
>> +                         unsigned long event, void *priv)
>> +{
>> +       struct rockchip_typec_phy *tcphy;
>> +       int value = *(int *)priv;
>> +       u8 is_dp, dfp;
>> +
>> +       tcphy = container_of(nb, struct rockchip_typec_phy, event_nb);
>> +       if (IS_ERR_OR_NULL(tcphy)) {
>> +               pr_err("initialization issue");
>> +               return -1;
>> +       }
>> +
>> +       tcphy->flip = GET_FLIP(value);
>> +       dfp = GET_DFP(value);
>> +       is_dp = GET_DP(value);
>> +       tcphy->map = GET_PIN_MAP(value);
>> +
>> +       if (event == 0) {
>> +               if (tcphy->mode == MODE_DISCONNECT)
>> +                       return 0;
>> +               tcphy->mode = MODE_DISCONNECT;
>> +       } else if (is_dp) {
>> +               if (tcphy->map & (PIN_MAP_B | PIN_MAP_D | PIN_MAP_F))
>> +                       tcphy->mode = MODE_DFP_USB3DP;
>> +               else
>> +                       tcphy->mode = MODE_DFP_DPONLY;
>> +       } else if (dfp) {
>> +               tcphy->mode = MODE_DFP_USBONLY;
>> +       } else {
>> +               tcphy->mode = MODE_UFP;
>> +       }
>> +
>> +       schedule_delayed_work_on(0, &tcphy->event_wq, 0);
>> +
>> +       return 0;
>> +}
>> +
>> +static void tcphy_event_wq(struct work_struct *work)
>> +{
>> +       struct rockchip_typec_phy *tcphy;
>> +
>> +       tcphy = container_of(work, struct rockchip_typec_phy, event_wq.work);
>> +       if (IS_ERR_OR_NULL(tcphy)) {
>> +               pr_err("initialization issue");
>> +               return;
>> +       }
>> +
>> +       switch (tcphy->mode) {
>> +       case MODE_DISCONNECT:
>> +               /* phy enter low power mode */
>> +               tcphy_phy_deinit(tcphy);
>> +               tcphy_dp_hpd(tcphy, 0);
>> +               break;
>> +       case MODE_UFP:
>> +               tcphy_phy_init(tcphy);
>> +               tcphy_usb3_init(tcphy);
>> +               tcphy_dp_hpd(tcphy, 0);
>> +               break;
>> +       case MODE_DFP_USBONLY:
>> +               tcphy_phy_init(tcphy);
>> +               tcphy_usb3_init(tcphy);
>> +               tcphy_dp_hpd(tcphy, 0);
>> +               break;
>> +       case MODE_DFP_DPONLY:
>> +       case MODE_DFP_USB2DP:
>> +               tcphy_phy_init(tcphy);
>> +               tcphy_dp_init(tcphy);
>> +               tcphy_dp_hpd(tcphy, 1);
>> +               break;
>> +       case MODE_DFP_USB3DP:
>> +               tcphy_phy_init(tcphy);
>> +               tcphy_usb3_init(tcphy);
>> +               tcphy_dp_init(tcphy);
>> +               tcphy_dp_hpd(tcphy, 1);
>> +               break;
>> +       }
>> +}
>> +
>> +int tcphy_parse_reg(struct rockchip_typec_phy *tcphy, struct device *dev)
>> +{
>> +       struct tcphy_grf_reg *exregs = &tcphy->exregs;
>> +       struct device_node *np = dev->of_node;
>> +       u32 len = 0, array[3];
>> +       int ret = 0;
>> +
>> +       PARSE_GRF_REG(con0);
>> +       PARSE_GRF_REG(con1);
>> +       PARSE_GRF_REG(con2);
>> +       PARSE_GRF_REG(status0);
>> +       PARSE_GRF_REG(status1);
>> +       return ret;
>> +}
>> +
>> +static int rockchip_typec_phy_probe(struct platform_device *pdev)
>> +{
>> +       struct device *dev = &pdev->dev;
>> +       struct rockchip_typec_phy *tcphy;
>> +       struct resource *res;
>> +       struct phy_provider *phy_provider;
>> +
>> +       tcphy = devm_kzalloc(dev, sizeof(*tcphy), GFP_KERNEL);
>> +       if (!tcphy)
>> +               return -ENOMEM;
>> +
>> +       tcphy->dev = dev;
>> +       platform_set_drvdata(pdev, tcphy);
>> +
>> +       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>> +       tcphy->base = devm_ioremap_resource(dev, res);
>> +       if (IS_ERR(tcphy->base)) {
>> +               dev_err(dev, "failed to remap phy regs\n");
>> +               return PTR_ERR(tcphy->base);
>> +       }
>> +       tcphy->grf_regs = syscon_regmap_lookup_by_phandle(dev->of_node,
>> +                                                       "rockchip,grf");
>> +       if (IS_ERR(tcphy->grf_regs)) {
>> +               dev_err(dev, "%s: could not find grf dt node\n", __func__);
>> +               return PTR_ERR(tcphy->grf_regs);
>> +       }
>> +
>> +       tcphy->clk_core = of_clk_get_by_name(dev->of_node, "tcpdcore");
>> +       if (IS_ERR(tcphy->clk_core)) {
>> +               dev_err(dev, "%s: could not get uphy core clock\n", __func__);
> nit: No real need for __func__.  That's useful to add in when you
> don't have a "dev" pointer and need a "pr_err" to show something that
> will help the user find the right line of code.
>
>> +               tcphy->clk_core = NULL;
> So is tcpdcore optional or required?  Bindings doc says "required" and
> the "dev_err" above implies required.  ...but then you don't return an
> error code.  That makes it optional.  ...but then you use it
> unconditional elsewhere in this file.  That makes it required.
>
> Summary: return an error here, don't just set to NULL.
>
>> +       }
>> +
>> +       tcphy->clk_ref = of_clk_get_by_name(dev->of_node, "tcpdphy_ref");
>> +       if (IS_ERR(tcphy->clk_core)) {
>> +               dev_err(dev, "%s: could not get uphy ref clock\n", __func__);
>> +               tcphy->clk_core = NULL;
> "if" test and NULL assignment are for wrong variables.
>
>> +       }
>> +
>> +       tcphy->phy_rst = devm_reset_control_get(dev, "tcphy_rst");
>> +       if (IS_ERR(tcphy->phy_rst)) {
>> +               dev_err(dev, "no phy_rst reset control found\n");
>> +               return PTR_ERR(tcphy->phy_rst);
>> +       }
>> +
>> +       tcphy->pipe_rst = devm_reset_control_get(dev, "tcphy_pipe_rst");
>> +       if (IS_ERR(tcphy->pipe_rst)) {
>> +               dev_err(dev, "no pipe_rst reset control found\n");
>> +               return PTR_ERR(tcphy->pipe_rst);
>> +       }
>> +
>> +       tcphy->uphy_rst = devm_reset_control_get(dev, "uphy_tcphy_rst");
>> +       if (IS_ERR(tcphy->uphy_rst)) {
>> +               dev_err(dev, "no uphy_rst reset control found\n");
>> +               return PTR_ERR(tcphy->uphy_rst);
>> +       }
>> +
>> +       tcphy_parse_reg(tcphy, dev);
>> +       tcphy->mode = MODE_DISCONNECT;
>> +
>> +       tcphy->phy = devm_phy_create(dev, NULL, NULL);
>> +
>> +       phy_set_drvdata(tcphy->phy, tcphy);
>> +
>> +       phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate);
>> +
>> +       /* register notifier for PD event */
>> +       ATOMIC_INIT_NOTIFIER_HEAD(&tcphy->notifier);
>> +       tcphy->event_nb.notifier_call = tcphy_pd_event;
>> +       INIT_DELAYED_WORK(&tcphy->event_wq, tcphy_event_wq);
>> +       tcphy_register_notifier(tcphy->phy, &tcphy->event_nb);
>> +
>> +       return PTR_ERR_OR_ZERO(phy_provider);
>> +}
>> +
>> +static int rockchip_typec_phy_remove(struct platform_device *pdev)
>> +{
>> +       return 0;
>> +}
> I believe that if you've got an empty remove function you can just remove it.
>
> ...but doesn't remove need to call tcphy_unregister_notifier?
>
>
>> +
>> +static const struct of_device_id rockchip_typec_phy_dt_ids[] = {
>> +       { .compatible = "rockchip,rk3399-typec-phy", },
>> +       {}
>> +};
>> +
>> +MODULE_DEVICE_TABLE(of, rockchip_typec_phy_dt_ids);
>> +
>> +static struct platform_driver rockchip_typec_phy_driver = {
>> +       .probe          = rockchip_typec_phy_probe,
>> +       .remove         = rockchip_typec_phy_remove,
>> +       .driver         = {
>> +               .name   = "rockchip-typec-phy",
>> +               .of_match_table = rockchip_typec_phy_dt_ids,
>> +       },
>> +};
>> +
>> +module_platform_driver(rockchip_typec_phy_driver);
>> +
>> +MODULE_AUTHOR("Kever Yang<kever.yang at rock-chips.com>");
> nit: space before "<"
>
>> +MODULE_AUTHOR("Chris Zhong<zyw at rock-chips.com>");
>> +MODULE_DESCRIPTION("Rockchip USB TYPE-C PHY driver");
>> +MODULE_LICENSE("GPL v2");
>> --
>> 2.6.3
>>
>
>




From zyw at rock-chips.com  Tue May 31 17:43:34 2016
From: zyw at rock-chips.com (Chris Zhong)
Date: Wed, 1 Jun 2016 08:43:34 +0800
Subject: [PATCH 2/6] Documentation: bindings: add dt doc for Rockchip USB
 Type-C PHY
In-Reply-To: <CAD=FV=W9iFXX_BfORP-9=8tnu9Ea_f2k1wK_T2j=ZAVA9cFSwg@mail.gmail.com>
References: <1464328939-8073-1-git-send-email-zyw@rock-chips.com>
 <1464328939-8073-3-git-send-email-zyw@rock-chips.com>
 <2812026.ptEv4ktvbn@phil> <5748094F.6030204@rock-chips.com>
 <CAD=FV=W9iFXX_BfORP-9=8tnu9Ea_f2k1wK_T2j=ZAVA9cFSwg@mail.gmail.com>
Message-ID: <574E2FB6.6010008@rock-chips.com>



On 06/01/2016 03:57 AM, Doug Anderson wrote:
> Chris,
>
> On Fri, May 27, 2016 at 1:46 AM, Chris Zhong <zyw at rock-chips.com> wrote:
>> Hi Heiko
>>
>>
>> On 05/27/2016 04:29 PM, Heiko Stuebner wrote:
>>> Hi Chris,
>>>
>>> Am Freitag, 27. Mai 2016, 14:02:15 schrieb Chris Zhong:
>>>> This patch adds a binding that describes the Rockchip USB Type-C PHY
>>>> for rk3399.
>>>>
>>>> Signed-off-by: Chris Zhong <zyw at rock-chips.com>
>>>> ---
>>>>
>>>>    .../devicetree/bindings/phy/phy-rockchip-typec.txt | 55
>>>> ++++++++++++++++++++++ 1 file changed, 55 insertions(+)
>>>>    create mode 100644
>>>> Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
>>>>
>>>> diff --git a/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
>>>> b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt new file
>>>> mode 100644
>>>> index 0000000..402f667
>>>> --- /dev/null
>>>> +++ b/Documentation/devicetree/bindings/phy/phy-rockchip-typec.txt
>>>> @@ -0,0 +1,55 @@
>>>> +ROCKCHIP type-c PHY
>>>> +
>>>> +Required properties:
>>>> + - compatible: should be "rockchip,rk3399-typec-phy"
>>>> + - reg : Address and length of the usb phy control register set
>>>> + - rockchip,grf : phandle to the syscon managing the "general
>>>> +   register files"
>>>> + - clocks : phandle + clock specifier for the phy clocks
>>>> + - clock-names: string, clock name, must be "tcpdcore", "tcpdphy_ref";
>>>> + - resets : a list of phandle + reset specifier pairs
>>>> + - reset-names : string reset name, must be:
>>>> +                "tcphy_rst", "tcphy_pipe_rst", "uphy_tcphy_rst"
> In other contexts I believe Heiko has requested that a suffix like
> "_rst" not be present in the names of reset signals.  We already know
> that this is a list of reset names so the "_rst" is redundant.
Yes, "_rst" is redundant.I will remove it next version.
>
>>>> + - #phy-cells: Must be 0.  See ./phy-bindings.txt for details.
>>>> + - rockchip,usb3phy*: phy registers embed in grf
>>>> +
>>>> +Example:
>>>> +       tcphy0: phy at ff7c0000 {
>>>> +               compatible = "rockchip,rk3399-typec-phy";
>>>> +               reg = <0x0 0xff7c0000 0x0 0x40000>;
>>>> +               #phy-cells = <0>;
>>>> +               rockchip,grf = <&grf>;
>>>> +               clocks = <&cru SCLK_UPHY0_TCPDCORE>,
>>>> +                        <&cru SCLK_UPHY0_TCPDPHY_REF>;
>>>> +               clock-names = "tcpdcore", "tcpdphy_ref";
>>>> +               resets = <&cru SRST_UPHY0>,
>>>> +                        <&cru SRST_UPHY0_PIPE_L00>,
>>>> +                        <&cru SRST_P_UPHY0_TCPHY>;
>>>> +               reset-names = "tcphy_rst", "tcphy_pipe_rst",
>>>> "uphy_tcphy_rst";
>>>> +               rockchip,usb3phy_con0 = <0x0e580 0 16>;
>>>> +               rockchip,usb3phy_con1 = <0x0e584 0 16>;
>>>> +               rockchip,usb3phy_con2 = <0x0e588 0 16>;
>>>> +               rockchip,usb3phy_status0 = <0x0e5c0 0 13>;
>>>> +               rockchip,usb3phy_status1 = <0x0e5c4 0 12>;
>>> please embedded this register data in the driver instead (not in the
>>> devicetree), matched against the compatible value.
>>> See Frank's usb2phy driver for reference if needed.
>> Okay, I will move them to driver file next version, Thanks.
> Just making sure: I saw a RESEND of your original version get posted,
> but nothing that addresses Heiko's comments, right?
>
> Also: note that bindings should be sent in the patch _before_ the
> code.  So instead of:
>    [1] phy: Add USB Type-C PHY driver for rk3399
>    [2] Documentation: bindings: add dt doc for Rockchip USB Type-C PHY
>    [3] drm/rockchip: vop: add cdn DP support for rk3399
>    [4] Documentation: bindings: add dt documentation for cdn DP controller
>
> You should have:
>    [1] Documentation: bindings: add dt doc for Rockchip USB Type-C PHY
>    [2] phy: Add USB Type-C PHY driver for rk3399
>    [3] Documentation: bindings: add dt documentation for cdn DP controller
>    [4] drm/rockchip: vop: add cdn DP support for rk3399
The first patch is lack of a header file, so I resend the patches, and 
did not change anything, I will do them in V1 version.
And I will change the  sequence of patches, Thanks for your comments.


>
> -Doug
>
>
>




From ykk at rock-chips.com  Tue May 31 18:47:02 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Wed, 1 Jun 2016 09:47:02 +0800
Subject: [PATCH v2 0/10] Add RK3399 eDP support and fix some bugs to
 analogix_dp driver.
In-Reply-To: <f6fb95e2-6357-5219-ea08-263c017955e4@osg.samsung.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
 <5746C321.9000707@rock-chips.com>
 <4e1c65f8-5a5b-dbb9-35fe-ef09c0758536@osg.samsung.com>
 <5747E648.6020100@rock-chips.com>
 <f6fb95e2-6357-5219-ea08-263c017955e4@osg.samsung.com>
Message-ID: <574E3E96.8090909@rock-chips.com>

Javier, Mark, Inki, Jingoo

On 06/01/2016 04:01 AM, Javier Martinez Canillas wrote:
> Hello Yakir,
>
> On 05/27/2016 02:16 AM, Yakir Yang wrote:
>> Hi Javier,
>>
>> On 05/26/2016 08:48 PM, Javier Martinez Canillas wrote:
>>> Hello Yakir,
>>>
>>> On 05/26/2016 05:34 AM, Yakir Yang wrote:
>>>> Hi Javier,
>>>>
>>>> On 05/24/2016 01:01 PM, Yakir Yang wrote:
>>>>> Hi all,
>>>>>
>>>>> This series have been posted about one month, still no comments, help here :(
>>>> This series works rightly on Rockchip platform, and most of them haven't touch the
>>>> common analogix_dp driver (except for the hotplug fixed). So i guess Exynos platform
>>>> should also happy with this changes.
>>>>
>>>> But not sure about that. So, is it possible that you could help to check this on Exynos
>>>> Chromebook, if so i would be very grateful about that.
>>>>
>>> Of course, I' ll test. Could you please provide me a branch that I can
>>> pull directly to avoid cherry-picking all the patches from the list?
>>>    
>> Ah, thanks a lot, I do have a tree https://github.com/yakir-Yang/linux/tree/fromlist/3399-edp
>>
> I tested your branch on an Exynos5800 Peach Pi Chromebook and display
> is working correctly. So feel free to add for the whole series:
>
> Tested-by: Javier Martinez Canillas <javier at osg.samsung.com>
Hi Javier,

Thank you very much, it's great to hear that, and make a big step 
forward.   :-D


Hi Mark, Inki, Jingoo

Those patches have been tested on Exynos and Rockchip platform rightly, and

This patches have been touched some rockchip_drm and analogix_dp core
code, it would be great to get some reviewed/acked from you. And for now 
this
patch-set have been tested on Rockchip and Exynos platform rightly, so 
could you
help to share some further comments here ;)


Thanks,
- Yakir
> Best regards,




From mark.yao at rock-chips.com  Tue May 31 18:48:38 2016
From: mark.yao at rock-chips.com (Mark yao)
Date: Wed, 1 Jun 2016 09:48:38 +0800
Subject: [PATCH v2 05/10] drm/rockchip: analogix_dp: add rk3399 eDP support
In-Reply-To: <1464066147-22734-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
 <1464066147-22734-1-git-send-email-ykk@rock-chips.com>
Message-ID: <574E3EF6.7020306@rock-chips.com>

On 2016?05?24? 13:02, Yakir Yang wrote:
> RK3399 and RK3288 shared the same eDP IP controller, only some light
> difference with VOP configure and GRF configure.
>
> Signed-off-by: Yakir Yang <ykk at rock-chips.com>
> ---
> Changes in v2:
> - rebase with drm-next, fix some conflicts
>
>   .../bindings/display/bridge/analogix_dp.txt        |  1 +
>   .../display/rockchip/analogix_dp-rockchip.txt      |  2 +-
>   drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    | 34 ++++++++++++++++++++--
>   include/drm/bridge/analogix_dp.h                   |  1 +
>   4 files changed, 35 insertions(+), 3 deletions(-)
>
>
Looks for me, So for the drm/rockchip side:

Acked-by: Mark Yao <mark.yao at rock-chips.com>

Thanks.

-- 
?ark Yao




From mark.yao at rock-chips.com  Tue May 31 18:57:50 2016
From: mark.yao at rock-chips.com (Mark yao)
Date: Wed, 1 Jun 2016 09:57:50 +0800
Subject: [PATCH v2 02/10] drm/rockchip: analogix_dp: split the lcdc select
 setting into device data
In-Reply-To: <1464066135-22605-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
 <1464066135-22605-1-git-send-email-ykk@rock-chips.com>
Message-ID: <574E411E.2040503@rock-chips.com>

On 2016?05?24? 13:02, Yakir Yang wrote:
> eDP controller need to declare which vop provide the video source,
> and it's defined in GRF registers.
>
> But different chips have different GRF register address, so we need to
> create a device data to declare the GRF messages for each chips.
>
> Signed-off-by: Yakir Yang<ykk at rock-chips.com>
Looks for me, So:

Acked-by: Mark Yao <mark.yao at rock-chips.com>

-- 
?ark Yao




From huangtao at rock-chips.com  Tue May 31 18:58:08 2016
From: huangtao at rock-chips.com (Huang, Tao)
Date: Wed, 1 Jun 2016 09:58:08 +0800
Subject: [PATCH 4/5] clocksource: rockchip: add support for rk3399 SoC
In-Reply-To: <574D9A66.4090209@linaro.org>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-5-git-send-email-wxt@rock-chips.com>
 <574CCCB4.1030001@linaro.org> <574D95AF.2020905@rock-chips.com>
 <574D9A66.4090209@linaro.org>
Message-ID: <574E4130.8090600@rock-chips.com>

Hi Daniel:
On 2016?05?31? 22:06, Daniel Lezcano wrote:
>>
>> @@ -46,15 +48,20 @@ static inline void __iomem *rk_base(struct
>> clock_event_device *ce)
>>   	return rk_timer(ce)->base;
>>   }
>>
>> +static inline void __iomem *rk_ctrl(struct clock_event_device *ce)
>> +{
>> +	return rk_timer(ce)->base + rk_timer(ce)->ctrl;
> 
> You can do a small optimization by pre-computing 'ctrl' at init time, so 
> no need to do this addition each time.

I understand what you mean, please see comment below.
And even we use ctrl as pointer, we still will get addition LDR other
then ADD.
This is disassemble code before:
   0:	f9408021 	ldr	x1, [x1,#256]
   4:	52800003 	mov	w3, #0x0
   8:	91004022 	add	x2, x1, #0x10
   c:	b9000043 	str	w3, [x2]
This is disassemble code after change:
   0:	52800003 	mov	w3, #0x0
   4:	f9408422 	ldr	x2, [x1,#264]
   8:	b9000043 	str	w3, [x2]
   c:	f9408021 	ldr	x1, [x1,#256]
Of course we can assume cache hit.

> 
>> +}
>> +
>>   static inline void rk_timer_disable(struct clock_event_device *ce)
>>   {
>> -	writel_relaxed(TIMER_DISABLE, rk_base(ce) + TIMER_CONTROL_REG);
>> +	writel_relaxed(TIMER_DISABLE, rk_ctrl(ce));
>>   }
>>
>>   static inline void rk_timer_enable(struct clock_event_device *ce, u32
>> flags)
>>   {
>>   	writel_relaxed(TIMER_ENABLE | TIMER_INT_UNMASK | flags,
>> -		       rk_base(ce) + TIMER_CONTROL_REG);
>> +		       rk_ctrl(ce));
>>   }
>>
>>   static void rk_timer_update_counter(unsigned long cycles,
>> @@ -179,4 +186,19 @@ out_unmap:
>>   	iounmap(bc_timer.base);
>>   }
>>
>> -CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
>> +static void __init rk3288_timer_init(struct device_node *np)
>> +{
>> +	bc_timer.ctrl = TIMER_CONTROL_REG3288;
>> +	rk_timer_init(np);
> 
> 	rk_timer_init(np);
> 	bc_timer.ctrl = bc_timer.base + TIMER_CONTROL_REG3288;

No. It's not such simple. You will access null pointer when
rk_timer_init, if we keep rk_timer_disable call in init or after
request_irq/clockevents_config_and_register and interrupt happen
immediately.

So the code maybe:
static void __init rk3288_timer_init(struct device_node *np)
{
	bc_timer.base = of_iomap(np, 0);
	if (!bc_timer.base) {
		pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
		return;
	}
	bc_timer.ctrl = bc_timer.base + TIMER_CONTROL_REG3288;
	rk_imter_init(np); // of course remove of_iomap from init.

Is this what you want?



From huangtao at rock-chips.com  Tue May 31 19:30:36 2016
From: huangtao at rock-chips.com (Huang, Tao)
Date: Wed, 1 Jun 2016 10:30:36 +0800
Subject: [PATCH 2/5] clocksource: rockchip: remove unnecessary clear irq
 before request_irq
In-Reply-To: <CAD=FV=U5zqU0CMeg1dDTYHrRqWAxTQO_xk2T7p09GJuj-Fn9Gw@mail.gmail.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-3-git-send-email-wxt@rock-chips.com>
 <574CC839.60608@linaro.org>
 <CAD=FV=U5zqU0CMeg1dDTYHrRqWAxTQO_xk2T7p09GJuj-Fn9Gw@mail.gmail.com>
Message-ID: <574E48CC.1040004@rock-chips.com>

Hi Doug:
On 2016?06?01? 01:03, Doug Anderson wrote:
> Hi,
> 
> On Mon, May 30, 2016 at 4:09 PM, Daniel Lezcano
> <daniel.lezcano at linaro.org> wrote:
>> On 05/25/2016 11:49 AM, Caesar Wang wrote:
>>>
>>> From: Huang Tao <huangtao at rock-chips.com>
>>>
>>> rk_timer_interrupt_clear and rk_timer_disable is unnecessary before
>>> request_irq. Timer should keep disabled before booting Linux.
>>
>>
>> That's true in the perfect world :/ Some version has u-boot letting the
>> timer with irq enabled, therefore as soon as request_irq is done, an irq
>> fires and leads to a kernel panic.
>>
>> On the other side, this timer is not used on the other rockchip version than
>> rk3399 because of no need of a broadcast timer, so removing these two lines
>> may be acceptable.
>>
>> Can try the changes with another board, eg rk3288 (and forcing to use this
>> timer). Can you do the test and confirm it does not break with different
>> version of u-boot ?
> 
> Actually, I'm not even sure that's true in a perfect world.  ;)  There
> are two main problems that might be lurking here:
> 
> 1. On exynos5 devices I've worked with, the private timer (MCT)
> actually shared the same physical counter with the ARM Architected
> Timer.  IIRC stopping or resetting the MCT had the effect of stopping
> / resetting the Arch Timer.  Is it the same for you?  As I understand
> it the Arch Timer isn't supposed to ever be stopped or reset.  If
> firmware left the timer stopped and the kernel happened to be compiled
> without support for the Rockchip timer (but had the Arch Timers) then
> things would be very broken.  Also the early kernel boot might be
> broken if the Arch Timer inits before the Rockchip timer.
> 
> NOTE: If your timer and the Arch Timer are totally separate then point
> #1 is not important.

We never use the timer which provide clock source of arch timer as
clockevent timer. If we do such stupid thing, when rk timer disabled,
the arch timer will stop too. Generally, we use this special timer as
clocksouce or never touch it again when it is running.

> 
> 
> 2. Historically in Chrome OS there's been an unofficial agreement that
> the firmware would start its high speed timer as soon as possible at
> bootup and that this could be used to (roughly) measure the time
> between the start of firmware and the start of the kernel.  That means
> that the kernel was expecting the timer to actually be running when it
> started up.  Yup, this is a bit of a hack and I'm not sure it's
> terribly well documented, but it does provide a reason that firmware
> might have left the timer running.

Why you chose the timer shared with Linux kernel, there are so many
timer? I think loader should do the right thing, uninit the resources
when it boot the kernel. I believe this code is lagacy from very old
chip such as rk2908 which is Cortex-A8. There are not arch timer, so the
loader may keep the timer running when enter kernel. Any way, if we
adopt the code suggested by Daniel, it is safe to keep the code.



From dianders at chromium.org  Tue May 31 19:36:55 2016
From: dianders at chromium.org (Doug Anderson)
Date: Tue, 31 May 2016 19:36:55 -0700
Subject: [PATCH 2/5] clocksource: rockchip: remove unnecessary clear irq
 before request_irq
In-Reply-To: <574E48CC.1040004@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-3-git-send-email-wxt@rock-chips.com>
 <574CC839.60608@linaro.org>
 <CAD=FV=U5zqU0CMeg1dDTYHrRqWAxTQO_xk2T7p09GJuj-Fn9Gw@mail.gmail.com>
 <574E48CC.1040004@rock-chips.com>
Message-ID: <CAD=FV=WA6OaOTM07+qxDJOW_TMsG06eAYwq5p5L_hw7PKd5MwA@mail.gmail.com>

Hi,

On Tue, May 31, 2016 at 7:30 PM, Huang, Tao <huangtao at rock-chips.com> wrote:
>> Actually, I'm not even sure that's true in a perfect world.  ;)  There
>> are two main problems that might be lurking here:
>>
>> 1. On exynos5 devices I've worked with, the private timer (MCT)
>> actually shared the same physical counter with the ARM Architected
>> Timer.  IIRC stopping or resetting the MCT had the effect of stopping
>> / resetting the Arch Timer.  Is it the same for you?  As I understand
>> it the Arch Timer isn't supposed to ever be stopped or reset.  If
>> firmware left the timer stopped and the kernel happened to be compiled
>> without support for the Rockchip timer (but had the Arch Timers) then
>> things would be very broken.  Also the early kernel boot might be
>> broken if the Arch Timer inits before the Rockchip timer.
>>
>> NOTE: If your timer and the Arch Timer are totally separate then point
>> #1 is not important.
>
> We never use the timer which provide clock source of arch timer as
> clockevent timer. If we do such stupid thing, when rk timer disabled,
> the arch timer will stop too. Generally, we use this special timer as
> clocksouce or never touch it again when it is running.

Ah, OK.  :)  I didn't go through and review / test the code.  I just
wanted to make sure we weren't going to run into the same bug I
remember running into before.  ;)


>> 2. Historically in Chrome OS there's been an unofficial agreement that
>> the firmware would start its high speed timer as soon as possible at
>> bootup and that this could be used to (roughly) measure the time
>> between the start of firmware and the start of the kernel.  That means
>> that the kernel was expecting the timer to actually be running when it
>> started up.  Yup, this is a bit of a hack and I'm not sure it's
>> terribly well documented, but it does provide a reason that firmware
>> might have left the timer running.
>
> Why you chose the timer shared with Linux kernel, there are so many
> timer? I think loader should do the right thing, uninit the resources
> when it boot the kernel. I believe this code is lagacy from very old
> chip such as rk2908 which is Cortex-A8. There are not arch timer, so the
> loader may keep the timer running when enter kernel. Any way, if we
> adopt the code suggested by Daniel, it is safe to keep the code.

If this is a separate / distinct timer than the main clocksource
timer, then you can ignore my comments.  ;)

...but obviously the comments from Daniel are much more important to
address and it sounds like you're all set for doing that.  :)

-Doug


From ykk at rock-chips.com  Tue May 31 19:52:25 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Wed, 1 Jun 2016 10:52:25 +0800
Subject: [RFC PATCH v1 1/2] drm/rockchip: add a notify event about vblank
 enable/disable
In-Reply-To: <20160531143615.GJ7231@phenom.ffwll.local>
References: <1464701856-8695-1-git-send-email-ykk@rock-chips.com>
 <1464701959-9428-1-git-send-email-ykk@rock-chips.com>
 <20160531143615.GJ7231@phenom.ffwll.local>
Message-ID: <574E4DE9.3030408@rock-chips.com>

Hi Daniel,

On 05/31/2016 10:36 PM, Daniel Vetter wrote:
> On Tue, May 31, 2016 at 09:39:19PM +0800, Yakir Yang wrote:
>> EDP PSR function is interesting in vblank enable or disable event,
>> so it would be great introduce a way to notify encoder about this
>> event.
>>
>> Signed-off-by: Yakir Yang <ykk at rock-chips.com>
> notifiers considered evil, especially if you add a global notifier for
> something that's very specific to a given crtc.
Oops, I haven't realized that. Yes, you're right, this is very specific to
a given crtc, that's bad :(
> I think the better fix would be add a suitable hook to drm_bridge to allow
> encoders to go into self refresh, and to wake them up from self-refresh
> again.
Sounds good, need to found a better way.

Thanks,
- Yakir
> -Daniel
>
>> ---
>>   drivers/gpu/drm/rockchip/Makefile              |  2 +-
>>   drivers/gpu/drm/rockchip/rockchip_drm_notify.c | 66 ++++++++++++++++++++++++++
>>   drivers/gpu/drm/rockchip/rockchip_drm_notify.h | 29 +++++++++++
>>   drivers/gpu/drm/rockchip/rockchip_drm_vop.c    |  5 ++
>>   4 files changed, 101 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.c
>>   create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.h
>>
>> diff --git a/drivers/gpu/drm/rockchip/Makefile b/drivers/gpu/drm/rockchip/Makefile
>> index 05d0713..49fee8c 100644
>> --- a/drivers/gpu/drm/rockchip/Makefile
>> +++ b/drivers/gpu/drm/rockchip/Makefile
>> @@ -3,7 +3,7 @@
>>   # Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
>>   
>>   rockchipdrm-y := rockchip_drm_drv.o rockchip_drm_fb.o \
>> -		rockchip_drm_gem.o rockchip_drm_vop.o
>> +		rockchip_drm_gem.o rockchip_drm_vop.o rockchip_drm_notify.o
>>   rockchipdrm-$(CONFIG_DRM_FBDEV_EMULATION) += rockchip_drm_fbdev.o
>>   
>>   obj-$(CONFIG_ROCKCHIP_ANALOGIX_DP) += analogix_dp-rockchip.o
>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.c b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c
>> new file mode 100644
>> index 0000000..84111d9
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.c
>> @@ -0,0 +1,66 @@
>> +#include "rockchip_drm_notify.h"
>> +
>> +static RAW_NOTIFIER_HEAD(vblank_chain);
>> +static DEFINE_MUTEX(vblank_lock);
>> +
>> +/**
>> + * rockchip_drm_vblank_enable - Send Vblank enable event. Will only enable send
>> + * Vblank if there are 1 or fewer notifiers.
>> + */
>> +void rockchip_drm_vblank_enable(void)
>> +{
>> +	mutex_lock(&vblank_lock);
>> +	raw_notifier_call_chain(&vblank_chain, VBLANK_ENABLE, NULL);
>> +	mutex_unlock(&vblank_lock);
>> +}
>> +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_enable);
>> +
>> +/**
>> + * rockchip_drm_vblank_disable - Send VBlank disable event.
>> + */
>> +void rockchip_drm_vblank_disable(void)
>> +{
>> +	mutex_lock(&vblank_lock);
>> +	raw_notifier_call_chain(&vblank_chain, VBLANK_DISABLE, NULL);
>> +	mutex_unlock(&vblank_lock);
>> +}
>> +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_disable);
>> +
>> +/**
>> + * rockchip_drm_vblank_register_notifier - Add notifier to Vblank notifiers.
>> + *
>> + * Enable notifiers are called when we enable/disable vblank. This can be done
>> + * through rockchip_drm_vblank_enable/disable or when there is more than one
>> + * sync notifier. Must call rockchip_drm_vblank_lock before calling this.
>> + * @nb The notifier to add
>> + */
>> +int rockchip_drm_vblank_register_notifier(struct notifier_block *nb)
>> +{
>> +	int ret = 0;
>> +
>> +	if (!nb)
>> +		return -EINVAL;
>> +
>> +	ret = raw_notifier_chain_register(&vblank_chain, nb);
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_register_notifier);
>> +
>> +/**
>> + * rockchip_drm_vblank_unregister_notifier - Remove notifier from Vblank
>> + * notifiers.
>> + *
>> + * Must call rockchip_drm_vblank_lock before calling this.
>> + * @nb The notifier to remove.
>> + */
>> +int rockchip_drm_vblank_unregister_notifier(struct notifier_block *nb)
>> +{
>> +	int ret = 0;
>> +
>> +	if (!nb)
>> +		return -EINVAL;
>> +
>> +	ret = raw_notifier_chain_unregister(&vblank_chain, nb);
>> +	return ret;
>> +}
>> +EXPORT_SYMBOL_GPL(rockchip_drm_vblank_unregister_notifier);
>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_notify.h b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h
>> new file mode 100644
>> index 0000000..2f28afa
>> --- /dev/null
>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_notify.h
>> @@ -0,0 +1,29 @@
>> +/*
>> + * Copyright (C) 2014 Google, Inc.
>> + *
>> + * This software is licensed under the terms of the GNU General Public
>> + * License version 2, as published by the Free Software Foundation, and
>> + * may be copied, distributed, and modified under those terms.
>> + *
>> + * This program is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>> + * GNU General Public License for more details.
>> + */
>> +
>> +#ifndef __ROCKCHIP_DRM_NOTIFY_H
>> +#define __ROCKCHIP_DRM_NOTIFY_H
>> +
>> +#include <linux/notifier.h>
>> +
>> +enum vblank_enable_op {
>> +	VBLANK_ENABLE = 0,
>> +	VBLANK_DISABLE,
>> +};
>> +
>> +void rockchip_drm_vblank_enable(void);
>> +void rockchip_drm_vblank_disable(void);
>> +int rockchip_drm_vblank_register_notifier(struct notifier_block *nb);
>> +int rockchip_drm_vblank_unregister_notifier(struct notifier_block *nb);
>> +
>> +#endif /* __ROCKCHIP_DRM_NOTIFY_H */
>> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>> index 257501f..fb6ce4b 100644
>> --- a/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_vop.c
>> @@ -35,6 +35,7 @@
>>   #include "rockchip_drm_gem.h"
>>   #include "rockchip_drm_fb.h"
>>   #include "rockchip_drm_vop.h"
>> +#include "rockchip_drm_notify.h"
>>   
>>   #define __REG_SET_RELAXED(x, off, mask, shift, v, write_mask) \
>>   		vop_mask_write(x, off, mask, shift, v, write_mask, true)
>> @@ -851,6 +852,8 @@ static int vop_crtc_enable_vblank(struct drm_crtc *crtc)
>>   
>>   	spin_unlock_irqrestore(&vop->irq_lock, flags);
>>   
>> +	rockchip_drm_vblank_enable();
>> +
>>   	return 0;
>>   }
>>   
>> @@ -867,6 +870,8 @@ static void vop_crtc_disable_vblank(struct drm_crtc *crtc)
>>   	VOP_INTR_SET_TYPE(vop, enable, FS_INTR, 0);
>>   
>>   	spin_unlock_irqrestore(&vop->irq_lock, flags);
>> +
>> +	rockchip_drm_vblank_disable();
>>   }
>>   
>>   static void vop_crtc_wait_for_update(struct drm_crtc *crtc)
>> -- 
>> 1.9.1
>>
>>




From ykk at rock-chips.com  Tue May 31 19:54:09 2016
From: ykk at rock-chips.com (Yakir Yang)
Date: Wed, 1 Jun 2016 10:54:09 +0800
Subject: [RFC PATCH v1 0/2]
In-Reply-To: <20160531143831.GK7231@phenom.ffwll.local>
References: <1464701856-8695-1-git-send-email-ykk@rock-chips.com>
 <20160531143831.GK7231@phenom.ffwll.local>
Message-ID: <574E4E51.1030308@rock-chips.com>

Hi Daniel,

On 05/31/2016 10:38 PM, Daniel Vetter wrote:
> On Tue, May 31, 2016 at 09:37:36PM +0800, Yakir Yang wrote:
>> The full name of PSR is Panel Self Refresh, panel device could refresh
>> itself with the hardware framebuffer in panel, this would make a lots
>> of sense to save the power consumption.
>>
>> For example, when desktop haven't change the context for a long time,
>> then we could refresh the data to the hardware framebuffer of panel,
>> and then let panel enter into PSR mode. After that system could poweroff
>> the LCDC controller and eDP controller, just let panel refresh the screen
>> by itself.
>>
>> It's hard to decide when panel should enter into PSR or exit from PSR, in
>> this time I chose to let the drm_vblank enable/disable event driver the PSR.
>>
>> This thread is based on Mark's RK3399 VOP thread[0] and my RK3399 eDP
>> thread[1].
>>
>> [0]: https://patchwork.kernel.org/patch/8886041/
>> [1]: https://patchwork.kernel.org/patch/9132713/
> Looks like you didn't wire up the drm_framebuffer->funcs->dirty callback
> for manual upload of simple clients like bootsplash or fbdev. I think
> that's needed. At least it's needed for every other manual upload dsi and
> edp psr implementation.
> -Daniel
That's great, thanks for your remind. Seems like userspace which does
frontbuffer rendering must call this ioctl to flush out the changes on
manual-update display outputs. It's helpful to hook this callback to
notify eDP refresh the eDP RFB(remote frame buffer).

But I think this is hard to used on Rockchip eDP controller, Rockchip eDP
driver just used two modes, Sink Device PSR_S0 (PSR inactive), and Sink
Device PSR_S2 (PSR active, display from RFB).

I think the "dirty" callback is only used when Sink device enter into PSR_S3
mode (PSR active, capture and display), need to update the remote frame
buffer. But on Rockchip platform the panel would be very easy to lose frame
in this PSR mode. I'm confused in this case, so I didn't enable that.

If we didn't enable the PSR_S3 mode, then we don't need to update the panel
remote frame buffer, so this "->dirty" callback would be unused in this 
case.

Thanks,
- Yakir
>> - Yakir
>> Thanks,
>>
>>
>> Yakir Yang (2):
>>    drm/rockchip: add a notify event about vblank enable/disable
>>    drm/rockchip: analogix: add eDP PSR function
>>
>>   drivers/gpu/drm/bridge/analogix/analogix_dp_core.c |  69 ++++++++++++++
>>   drivers/gpu/drm/bridge/analogix/analogix_dp_core.h |   5 +
>>   drivers/gpu/drm/bridge/analogix/analogix_dp_reg.c  |  54 +++++++++++
>>   drivers/gpu/drm/bridge/analogix/analogix_dp_reg.h  |  28 ++++++
>>   drivers/gpu/drm/rockchip/Makefile                  |   2 +-
>>   drivers/gpu/drm/rockchip/analogix_dp-rockchip.c    |  65 +++++++++++++
>>   drivers/gpu/drm/rockchip/rockchip_drm_notify.c     | 105 +++++++++++++++++++++
>>   drivers/gpu/drm/rockchip/rockchip_drm_notify.h     |  33 +++++++
>>   drivers/gpu/drm/rockchip/rockchip_drm_vop.c        |  96 +++++++++++++++++++
>>   drivers/gpu/drm/rockchip/rockchip_drm_vop.h        |   3 +
>>   drivers/gpu/drm/rockchip/rockchip_vop_reg.c        |   2 +
>>   include/drm/bridge/analogix_dp.h                   |   3 +
>>   12 files changed, 464 insertions(+), 1 deletion(-)
>>   create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.c
>>   create mode 100644 drivers/gpu/drm/rockchip/rockchip_drm_notify.h
>>
>> -- 
>> 1.9.1
>>
>>




From wenrui.li at rock-chips.com  Tue May 31 19:56:53 2016
From: wenrui.li at rock-chips.com (Wenrui Li)
Date: Wed, 1 Jun 2016 10:56:53 +0800
Subject: [PATCH 2/2] pci: Add PCIe driver for Rockchip Soc
In-Reply-To: <57483CAA.8000005@arm.com>
References: <1463740105-7061-1-git-send-email-shawn.lin@rock-chips.com>
 <1463740156-7148-1-git-send-email-shawn.lin@rock-chips.com>
 <57483CAA.8000005@arm.com>
Message-ID: <574E4EF5.7040005@rock-chips.com>

Hi:

On 2016/5/27 20:25, Marc Zyngier Wrote:
> [+Lorenzo]
>
> On 20/05/16 11:29, Shawn Lin wrote:
>> RK3399 has a PCIe controller which can be used as Root Complex.
>> This driver supports a PCIe controller as Root Complex mode.
>>

[....]

>> +static int rockchip_pcie_init_irq_domain(struct rockchip_pcie_port *pp)
>> +{
>> +	struct device *dev = pp->dev;
>> +	struct device_node *node = dev->of_node;
>> +	struct device_node *pcie_intc_node =  of_get_next_child(node, NULL);
>
> That's really ugly, as it depends on the layout of your DT.
>
>> +
>> +	if (!pcie_intc_node) {
>> +		dev_err(dev, "No PCIe Intc node found\n");
>> +		return PTR_ERR(pcie_intc_node);
>> +	}
>> +	pp->irq_domain = irq_domain_add_linear(pcie_intc_node, 4,
>> +					       &intx_domain_ops, pp);
>
> Why can't you just register your host controller as the interrupt
> controller? You don't need an intermediate node for that.

OK, the child node is really no need here, we will use the host 
controller as interrupt controller next patch. Thanks!

>
>> +	if (!pp->irq_domain) {
>> +		dev_err(dev, "Failed to get a INTx IRQ domain\n");
>> +		return PTR_ERR(pp->irq_domain);
>> +	}
>> +
>> +	return 0;
>> +}
>> +
>> +static irqreturn_t rockchip_pcie_subsys_irq_handler(int irq, void *arg)
>> +{
>> +	struct rockchip_pcie_port *pp = arg;
>> +	u32 reg;
>> +	u32 sub_reg;
>> +
>> +	reg = pcie_read(pp, PCIE_CLIENT_INT_STATUS);
>> +	if (reg & LOC_INT) {
>> +		dev_dbg(pp->dev, "local interrupt recived\n");
>> +		sub_reg = pcie_read(pp, PCIE_CORE_INT_STATUS);
>> +		if (sub_reg & PRFPE)
>> +			dev_dbg(pp->dev, "Parity error detected while reading from the PNP Receive FIFO RAM\n");
>> +
>> +		if (sub_reg & CRFPE)
>> +			dev_dbg(pp->dev, "Parity error detected while reading from the Completion Receive FIFO RAM\n");
>> +
>> +		if (sub_reg & RRPE)
>> +			dev_dbg(pp->dev, "Parity error detected while reading from Replay Buffer RAM\n");
>> +
>> +		if (sub_reg & PRFO)
>> +			dev_dbg(pp->dev, "Overflow occurred in the PNP Receive FIFO\n");
>> +
>> +		if (sub_reg & CRFO)
>> +			dev_dbg(pp->dev, "Overflow occurred in the Completion Receive FIFO\n");
>> +
>> +		if (sub_reg & RT)
>> +			dev_dbg(pp->dev, "Replay timer timed out\n");
>> +
>> +		if (sub_reg & RTR)
>> +			dev_dbg(pp->dev, "Replay timer rolled over after 4 transmissions of the same TLP\n");
>> +
>> +		if (sub_reg & PE)
>> +			dev_dbg(pp->dev, "Phy error detected on receive side\n");
>> +
>> +		if (sub_reg & MTR)
>> +			dev_dbg(pp->dev, "Malformed TLP received from the link\n");
>> +
>> +		if (sub_reg & UCR)
>> +			dev_dbg(pp->dev, "Malformed TLP received from the link\n");
>> +
>> +		if (sub_reg & FCE)
>> +			dev_dbg(pp->dev, "An error was observed in the flow control advertisements from the other side\n");
>> +
>> +		if (sub_reg & CT)
>> +			dev_dbg(pp->dev, "A request timed out waiting for completion\n");
>> +
>> +		if (sub_reg & UTC)
>> +			dev_dbg(pp->dev, "Unmapped TC error\n");
>> +
>> +		if (sub_reg & MMVC)
>> +			dev_dbg(pp->dev, "MSI mask register changes\n");
>> +
>> +		pcie_write(pp, sub_reg, PCIE_CORE_INT_STATUS);
>> +	}
>> +
>> +	pcie_write(pp, reg, PCIE_CLIENT_INT_STATUS);
>> +
>> +	return IRQ_HANDLED;
>> +}

[....]

>> +static irqreturn_t rockchip_pcie_legacy_int_handler(int irq, void *arg)
>> +{
>> +	struct rockchip_pcie_port *pp = arg;
>> +	u32 reg;
>> +
>> +	reg = pcie_read(pp, PCIE_CLIENT_INT_STATUS);
>> +	reg = (reg & ROCKCHIP_PCIE_RPIFR1_INTR_MASK) >>
>> +	       ROCKCHIP_PCIE_RPIFR1_INTR_SHIFT;
>> +	generic_handle_irq(irq_find_mapping(pp->irq_domain, ffs(reg)));
>
> NAK. What you have here is a chained interrupt controller, please
> implement it as such.

Your mean is use handle_nested_irq instead of generic_handle_irq here?
But, I found all other pci host controller drivers use this api.

>
>> +
>> +	pcie_write(pp, reg, PCIE_CLIENT_INT_STATUS);
>> +	return IRQ_HANDLED;
>> +}
>> +

[...]

>> +static struct platform_driver rockchip_pcie_driver = {
>> +	.driver = {
>> +		.name = "rockchip-pcie",
>> +		.of_match_table = rockchip_pcie_of_match,
>> +		.suppress_bind_attrs = true,
>> +	},
>> +	.probe = rockchip_pcie_probe,
>> +	.remove = rockchip_pcie_remove,
>> +};
>> +module_platform_driver(rockchip_pcie_driver);
>> +
>> +MODULE_AUTHOR("Rockchip Inc");
>> +MODULE_DESCRIPTION("Rockchip AXI PCIe driver");
>> +MODULE_LICENSE("GPL v2");
>>
>
> This definitely requires some rework for both the interrupt and MSI
> parts. I'll leave Lorenzo to comment on the PCI side of things.
>
> Thanks,
>
> 	M.
>

Best Regards,
Li



From mark.yao at rock-chips.com  Tue May 31 20:51:26 2016
From: mark.yao at rock-chips.com (Mark yao)
Date: Wed, 1 Jun 2016 11:51:26 +0800
Subject: [PATCH v2 09/10] drm/rockchip: analogix_dp: update the comments
 about why need to hardcode VOP output mode
In-Reply-To: <1464066168-22906-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
 <1464066168-22906-1-git-send-email-ykk@rock-chips.com>
Message-ID: <574E5BBE.7060304@rock-chips.com>

On 2016?05?24? 13:02, Yakir Yang wrote:
> The hardware IC designed that VOP must output the RGB10 video format to
> eDP contoller, and if eDP panel only support RGB8, then eDP contoller
> should cut down the video data, not via VOP contoller, that's why we need
> to hardcode the VOP output mode to RGA10 here.
>
> Signed-off-by: Yakir Yang<ykk at rock-chips.com>
Looks for me, So:

Acked-by: Mark Yao <mark.yao at rock-chips.com>

-- 
?ark Yao




From mark.yao at rock-chips.com  Tue May 31 20:52:04 2016
From: mark.yao at rock-chips.com (Mark yao)
Date: Wed, 1 Jun 2016 11:52:04 +0800
Subject: [PATCH v2 08/10] drm/rockchip: analogix_dp: correct the connector
 display color format and bpc
In-Reply-To: <1464066164-22863-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
 <1464066164-22863-1-git-send-email-ykk@rock-chips.com>
Message-ID: <574E5BE4.7050003@rock-chips.com>

On 2016?05?24? 13:02, Yakir Yang wrote:
> Rockchip VOP couldn't output YUV video format for eDP controller, so
> when driver detect connector support YUV video format, we need to hack
> it down to RGB888.
>
> Signed-off-by: Yakir Yang <ykk at rock-chips.com>
> ---
> Changes in v2: None
>
>   drivers/gpu/drm/rockchip/analogix_dp-rockchip.c | 19 +++++++++++++++++++
>   1 file changed, 19 insertions(+)
>
> diff --git a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> index f29ca3d..910cceb 100644
> --- a/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> +++ b/drivers/gpu/drm/rockchip/analogix_dp-rockchip.c
> @@ -97,6 +97,24 @@ static int rockchip_dp_powerdown(struct analogix_dp_plat_data *plat_data)
>   	return 0;
>   }
>   
> +static enum drm_mode_status
> +rockchip_dp_mode_valid(struct analogix_dp_plat_data *plat_data,
> +		       struct drm_connector *connector,
> +		       struct drm_display_mode *mode)
> +{
> +	struct drm_display_info *di = &connector->display_info;
> +
> +	if (di->color_formats & DRM_COLOR_FORMAT_YCRCB444 ||
> +	    di->color_formats & DRM_COLOR_FORMAT_YCRCB422) {
> +		di->color_formats &= ~(DRM_COLOR_FORMAT_YCRCB422 |
> +				       DRM_COLOR_FORMAT_YCRCB444);
> +		di->color_formats |= DRM_COLOR_FORMAT_RGB444;
> +		di->bpc = 8;
> +	}
> +
> +	return MODE_OK;
> +}
> +
>   static bool
>   rockchip_dp_drm_encoder_mode_fixup(struct drm_encoder *encoder,
>   				   const struct drm_display_mode *mode,
> @@ -306,6 +324,7 @@ static int rockchip_dp_bind(struct device *dev, struct device *master,
>   	dp->plat_data.subdev_type = dp_data->chip_type;
>   	dp->plat_data.power_on = rockchip_dp_poweron;
>   	dp->plat_data.power_off = rockchip_dp_powerdown;
> +	dp->plat_data.mode_valid = rockchip_dp_mode_valid;
>   
>   	return analogix_dp_bind(dev, dp->drm_dev, &dp->plat_data);
>   }
Looks for me, So:

Acked-by: Mark Yao <mark.yao at rock-chips.com>

-- 
?ark Yao




From mark.yao at rock-chips.com  Tue May 31 20:53:12 2016
From: mark.yao at rock-chips.com (Mark yao)
Date: Wed, 1 Jun 2016 11:53:12 +0800
Subject: [PATCH v2 06/10] drm/rockchip: analogix_dp: make panel detect to
 an optional action
In-Reply-To: <1464066155-22777-1-git-send-email-ykk@rock-chips.com>
References: <1464066086-21967-1-git-send-email-ykk@rock-chips.com>
 <1464066155-22777-1-git-send-email-ykk@rock-chips.com>
Message-ID: <574E5C28.1030504@rock-chips.com>

On 2016?05?24? 13:02, Yakir Yang wrote:
> Some boards don't need to declare a panel device node, like the
> display interface is DP monitors, so it's necessary to make the
> panel detect to an optional action.
>
> Signed-off-by: Yakir Yang<ykk at rock-chips.com>
> ---
Looks for me, So:

Acked-by: Mark Yao <mark.yao at rock-chips.com>

-- 
?ark Yao




From daniel.lezcano at linaro.org  Tue May 31 23:16:41 2016
From: daniel.lezcano at linaro.org (Daniel Lezcano)
Date: Wed, 1 Jun 2016 08:16:41 +0200
Subject: [PATCH 4/5] clocksource: rockchip: add support for rk3399 SoC
In-Reply-To: <574E4130.8090600@rock-chips.com>
References: <1464169802-6033-1-git-send-email-wxt@rock-chips.com>
 <1464169802-6033-5-git-send-email-wxt@rock-chips.com>
 <574CCCB4.1030001@linaro.org> <574D95AF.2020905@rock-chips.com>
 <574D9A66.4090209@linaro.org> <574E4130.8090600@rock-chips.com>
Message-ID: <574E7DC9.4000102@linaro.org>

On 06/01/2016 03:58 AM, Huang, Tao wrote:
> Hi Daniel:
> On 2016?05?31? 22:06, Daniel Lezcano wrote:

[ ... ]

>>> -CLOCKSOURCE_OF_DECLARE(rk_timer, "rockchip,rk3288-timer", rk_timer_init);
>>> +static void __init rk3288_timer_init(struct device_node *np)
>>> +{
>>> +	bc_timer.ctrl = TIMER_CONTROL_REG3288;
>>> +	rk_timer_init(np);
>>
>> 	rk_timer_init(np);
>> 	bc_timer.ctrl = bc_timer.base + TIMER_CONTROL_REG3288;
>
> No. It's not such simple. You will access null pointer when
> rk_timer_init, if we keep rk_timer_disable call in init or after
> request_irq/clockevents_config_and_register and interrupt happen
> immediately.
>
> So the code maybe:
> static void __init rk3288_timer_init(struct device_node *np)
> {
> 	bc_timer.base = of_iomap(np, 0);
> 	if (!bc_timer.base) {
> 		pr_err("Failed to get base address for '%s'\n", TIMER_NAME);
> 		return;
> 	}
> 	bc_timer.ctrl = bc_timer.base + TIMER_CONTROL_REG3288;
> 	rk_imter_init(np); // of course remove of_iomap from init.
>
> Is this what you want?

Not necessarily. There are plenty of variants.

eg. rk_timer_init(np, TIMER_CONTROL_REG3288);



-- 
  <http://www.linaro.org/> Linaro.org ? Open source software for ARM SoCs

Follow Linaro:  <http://www.facebook.com/pages/Linaro> Facebook |
<http://twitter.com/#!/linaroorg> Twitter |
<http://www.linaro.org/linaro-blog/> Blog



