* [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api
@ 2015-10-12 12:48 Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 1/7] mmc: core: move ocr-bit to voltage translation into separate function Heiko Stuebner
` (7 more replies)
0 siblings, 8 replies; 12+ messages in thread
From: Heiko Stuebner @ 2015-10-12 12:48 UTC (permalink / raw)
To: ulf.hansson
Cc: jh80.chung, linux-mmc, linux-arm-kernel, linux-rockchip, dianders,
amstan, Heiko Stuebner
This series resurrects and adapts some individual patches whose sum
enable the dw_mmc hosts on Rockchip socs to tune clock phases using
the generic phase api (rk3288 and following have this capability).
The changes to the original mmc-phase clocks are expanded by further
findings resulting from devices being used in the field.
Similarly the regulator handling changes do use the brand new
regulator_set_voltage_triplet call to allow specifying lower and upper
limits. One possible point of discussion are the two voltage ranges
that are tried for the 3.3V signal level. Trying to stay near vmmc
at first and only then opening the range to the full 2.7-3.6V.
This mainly circumvents a shortcoming of the regulator voltage
setting, in that even with regulator_set_voltage_triplet the regulator
framework will take the lowest possible voltage when the possible
voltages are below the target voltage. While it may be ideal to solve
this on the regulator side, I'm not seeing this appearing in the short
term, mainly because all regulator parts (including regulator drivers)
are keyed to selecting the lowest voltage from the range, while on the
mmc side we know which voltages may work and trying this in two steps
does not create to much overhead, as unsupported voltages are already
filtered out by the regulator_is_voltage_selected calls.
changes since v2:
- use host->ios.vdd to read vmmc from instead of requiring the vmmc
regulator. Suggested by Ulf this makes the voltage setting still work
even if only the vqmmc but not the vmmc regulator is supplied.
- add Acks from Jaehoon Chung to the dw_mmc parts
- drop first two clock patches that already got applied to the mmc tree
changes since v1:
- address comment from Jaehoon Chung and keep this local to Rockchip
for the time being
- address comments from Ulf and Doug in making it more explicit
that the two-step 3.3V voltage setting essentially works around
a limitation of regulator_set_voltage_triplet
Alexandru M Stan (3):
mmc: dw_mmc-rockchip: dt-binding: Add tuning related things
mmc: dw_mmc-rockchip: MMC tuning with the clock phase framework
ARM: dts: rockchip: Add drive/sample clocks for rk3288 dw_mmc devices
Douglas Anderson (2):
mmc: core: Add mmc_regulator_set_vqmmc()
mmc: dw_mmc: Use mmc_regulator_set_vqmmc in
start_signal_voltage_switch
Heiko Stuebner (2):
mmc: core: move ocr-bit to voltage translation into separate function
ARM: dts: rockchip: add tuning related settings to veyron devices
.../devicetree/bindings/mmc/rockchip-dw-mshc.txt | 13 ++
arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi | 7 +-
arch/arm/boot/dts/rk3288-veyron.dtsi | 6 +
arch/arm/boot/dts/rk3288.dtsi | 20 ++-
drivers/mmc/core/core.c | 129 ++++++++++++++--
drivers/mmc/host/dw_mmc-rockchip.c | 162 +++++++++++++++++++++
drivers/mmc/host/dw_mmc.c | 17 +--
include/linux/mmc/host.h | 7 +
8 files changed, 325 insertions(+), 36 deletions(-)
--
2.6.1
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3 1/7] mmc: core: move ocr-bit to voltage translation into separate function
2015-10-12 12:48 [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Heiko Stuebner
@ 2015-10-12 12:48 ` Heiko Stuebner
2015-10-12 13:26 ` kbuild test robot
[not found] ` <1444654110-32293-2-git-send-email-heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
2015-10-12 12:48 ` [PATCH v3 2/7] mmc: core: Add mmc_regulator_set_vqmmc() Heiko Stuebner
` (6 subsequent siblings)
7 siblings, 2 replies; 12+ messages in thread
From: Heiko Stuebner @ 2015-10-12 12:48 UTC (permalink / raw)
To: ulf.hansson
Cc: jh80.chung, linux-mmc, linux-arm-kernel, linux-rockchip, dianders,
amstan, Heiko Stuebner
We will shortly need the calculation of an ocr-bit to the actual
voltage in a second place too, so move it from mmc_regulator_set_ocr
to a common function mmc_ocrbitnum_to_vdd to make that possible.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/mmc/core/core.c | 51 +++++++++++++++++++++++++++++++++----------------
1 file changed, 35 insertions(+), 16 deletions(-)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 0520064..548b5e1 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1265,6 +1265,40 @@ u32 mmc_vddrange_to_ocrmask(int vdd_min, int vdd_max)
}
EXPORT_SYMBOL(mmc_vddrange_to_ocrmask);
+/**
+ * mmc_ocrbitnum_to_vdd - Convert a OCR bit number to its voltage
+ * @vdd_bit: OCR bit number
+ * @min_uV: minimum voltage value (mV)
+ * @max_uV: maximum voltage value (mV)
+ *
+ * This function returns the voltage range according to the provided OCR
+ * bit number. If conversion is not possible a negative errno value returned.
+ */
+static int mmc_ocrbitnum_to_vdd(int vdd_bit, int *min_uV, int *max_uV)
+{
+ int tmp;
+
+ if (!vdd_bit)
+ return -EINVAL;
+
+ /*
+ * REVISIT mmc_vddrange_to_ocrmask() may have set some
+ * bits this regulator doesn't quite support ... don't
+ * be too picky, most cards and regulators are OK with
+ * a 0.1V range goof (it's a small error percentage).
+ */
+ tmp = vdd_bit - ilog2(MMC_VDD_165_195);
+ if (tmp == 0) {
+ *min_uV = 1650 * 1000;
+ *max_uV = 1950 * 1000;
+ } else {
+ *min_uV = 1900 * 1000 + tmp * 100 * 1000;
+ *max_uV = *min_uV + 100 * 1000;
+ }
+
+ return 0;
+}
+
#ifdef CONFIG_OF
/**
@@ -1401,22 +1435,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
int min_uV, max_uV;
if (vdd_bit) {
- int tmp;
-
- /*
- * REVISIT mmc_vddrange_to_ocrmask() may have set some
- * bits this regulator doesn't quite support ... don't
- * be too picky, most cards and regulators are OK with
- * a 0.1V range goof (it's a small error percentage).
- */
- tmp = vdd_bit - ilog2(MMC_VDD_165_195);
- if (tmp == 0) {
- min_uV = 1650 * 1000;
- max_uV = 1950 * 1000;
- } else {
- min_uV = 1900 * 1000 + tmp * 100 * 1000;
- max_uV = min_uV + 100 * 1000;
- }
+ mmc_ocrbitnum_to_vdd(vdd_bit, &min_uV, &max_uV);
result = regulator_set_voltage(supply, min_uV, max_uV);
if (result == 0 && !mmc->regulator_enabled) {
--
2.6.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 2/7] mmc: core: Add mmc_regulator_set_vqmmc()
2015-10-12 12:48 [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 1/7] mmc: core: move ocr-bit to voltage translation into separate function Heiko Stuebner
@ 2015-10-12 12:48 ` Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 3/7] mmc: dw_mmc: Use mmc_regulator_set_vqmmc in start_signal_voltage_switch Heiko Stuebner
` (5 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Heiko Stuebner @ 2015-10-12 12:48 UTC (permalink / raw)
To: ulf.hansson
Cc: jh80.chung, linux-mmc, linux-arm-kernel, linux-rockchip, dianders,
amstan, Heiko Stuebner
From: Douglas Anderson <dianders@chromium.org>
This adds logic to the MMC core to set VQMMC. This is expected to be
called by MMC drivers like dw_mmc as part of (or instead of) their
start_signal_voltage_switch() callback.
A few notes:
* When setting the signal voltage to 3.3V we do our best to make VQMMC
and VMMC match. It's been reported that this makes some old cards
happy since they were tested back in the day before UHS when VQMMC
and VMMC were provided by the same regulator. A nice side effect of
this is that we don't end up on the hairy edge of VQMMC (2.7V),
which some EEs claim is a little too close to the minimum for
comfort.
This is done in two steps. At first we try to find a VQMMC within
a 0.3V tolerance of VMMC and if this is not supported by the
supplying regulator we try to find a suitable voltage within the
whole 2.7V-3.6V area of the spec.
* The two step approach is currently necessary, as the used
regulator_set_voltage_triplet(min, target, max) uses a simple
implementation that just tries two basic steps:
regulator_set_voltage(target, max);
regulator_set_voltage(min, target);
So with only one step with 2.7-3.6V borders, if a suitable voltage
is a bit below VMMC, we would directly get the lowest 2.7V
which some boards (like Rockchips) don't like at all.
* When setting the signal voltage to 1.8V or 1.2V we aim for that
specific voltage instead of picking the lowest one in the range.
* We very purposely don't print errors in mmc_regulator_set_vqmmc().
There are cases where the MMC core will try several different
voltages and we don't want to pollute the logs.
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
drivers/mmc/core/core.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++
include/linux/mmc/host.h | 7 +++++
2 files changed, 85 insertions(+)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 548b5e1..da0a243 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1456,6 +1456,84 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
}
EXPORT_SYMBOL_GPL(mmc_regulator_set_ocr);
+static int mmc_regulator_set_voltage_if_supported(struct regulator *regulator,
+ int min_uV, int target_uV,
+ int max_uV)
+{
+ /*
+ * Check if supported first to avoid errors since we may try several
+ * signal levels during power up and don't want to show errors.
+ */
+ if (!regulator_is_supported_voltage(regulator, min_uV, max_uV))
+ return -EINVAL;
+
+ return regulator_set_voltage_triplet(regulator, min_uV, target_uV,
+ max_uV);
+}
+
+/**
+ * mmc_regulator_set_vqmmc - Set VQMMC as per the ios
+ *
+ * For 3.3V signaling, we try to match VQMMC to VMMC as closely as possible.
+ * That will match the behavior of old boards where VQMMC and VMMC were supplied
+ * by the same supply. The Bus Operating conditions for 3.3V signaling in the
+ * SD card spec also define VQMMC in terms of VMMC.
+ * If this is not possible we'll try the full 2.7-3.6V of the spec.
+ *
+ * For 1.2V and 1.8V signaling we'll try to get as close as possible to the
+ * requested voltage. This is definitely a good idea for UHS where there's a
+ * separate regulator on the card that's trying to make 1.8V and it's best if
+ * we match.
+ *
+ * This function is expected to be used by a controller's
+ * start_signal_voltage_switch() function.
+ */
+int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct device *dev = mmc_dev(mmc);
+ int ret, volt, min_uV, max_uV;
+
+ /* If no vqmmc supply then we can't change the voltage */
+ if (IS_ERR(mmc->supply.vqmmc))
+ return -EINVAL;
+
+ switch (ios->signal_voltage) {
+ case MMC_SIGNAL_VOLTAGE_120:
+ return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
+ 1100000, 1200000, 1300000);
+ case MMC_SIGNAL_VOLTAGE_180:
+ return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
+ 1700000, 1800000, 1950000);
+ case MMC_SIGNAL_VOLTAGE_330:
+ ret = mmc_ocrbitnum_to_vdd(mmc->ios.vdd, &volt, &max_uV);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(dev, "%s: found vmmc voltage range of %d-%duV\n",
+ __func__, volt, max_uV);
+
+ min_uV = max(volt - 300000, 2700000);
+ max_uV = min(max_uV + 200000, 3600000);
+
+ /*
+ * Due to a limitation in the current implementation of
+ * regulator_set_voltage_triplet() which is taking the lowest
+ * voltage possible if below the target, search for a suitable
+ * voltage in two steps and try to stay close to vmmc
+ * with a 0.3V tolerance at first.
+ */
+ if (!mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
+ min_uV, volt, max_uV))
+ return 0;
+
+ return mmc_regulator_set_voltage_if_supported(mmc->supply.vqmmc,
+ 2700000, volt, 3600000);
+ default:
+ return -EINVAL;
+ }
+}
+EXPORT_SYMBOL_GPL(mmc_regulator_set_vqmmc);
+
#endif /* CONFIG_REGULATOR */
int mmc_regulator_get_supply(struct mmc_host *mmc)
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index 83b81fd..a2a78eb 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -423,6 +423,7 @@ int mmc_regulator_get_ocrmask(struct regulator *supply);
int mmc_regulator_set_ocr(struct mmc_host *mmc,
struct regulator *supply,
unsigned short vdd_bit);
+int mmc_regulator_set_vqmmc(struct mmc_host *mmc, struct mmc_ios *ios);
#else
static inline int mmc_regulator_get_ocrmask(struct regulator *supply)
{
@@ -435,6 +436,12 @@ static inline int mmc_regulator_set_ocr(struct mmc_host *mmc,
{
return 0;
}
+
+static inline int mmc_regulator_set_vqmmc(struct mmc_host *mmc,
+ struct mmc_ios *ios)
+{
+ return -EINVAL;
+}
#endif
int mmc_regulator_get_supply(struct mmc_host *mmc);
--
2.6.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 3/7] mmc: dw_mmc: Use mmc_regulator_set_vqmmc in start_signal_voltage_switch
2015-10-12 12:48 [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 1/7] mmc: core: move ocr-bit to voltage translation into separate function Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 2/7] mmc: core: Add mmc_regulator_set_vqmmc() Heiko Stuebner
@ 2015-10-12 12:48 ` Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 4/7] mmc: dw_mmc-rockchip: dt-binding: Add tuning related things Heiko Stuebner
` (4 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Heiko Stuebner @ 2015-10-12 12:48 UTC (permalink / raw)
To: ulf.hansson
Cc: jh80.chung, linux-mmc, linux-arm-kernel, linux-rockchip, dianders,
amstan, Heiko Stuebner
From: Douglas Anderson <dianders@chromium.org>
We've introduced a new helper in the MMC core:
mmc_regulator_set_vqmmc(). Let's use this in dw_mmc. Using this new
helper has some advantages:
1. We get the mmc_regulator_set_vqmmc() behavior of trying to match
VQMMC and VMMC when the signal voltage is 3.3V. This ensures max
compatibility.
2. We get rid of a few more warnings when probing unsupported
voltages.
3. We get rid of some non-dw_mmc specific code in dw_mmc.
Signed-off-by: Douglas Anderson <dianders@chromium.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
drivers/mmc/host/dw_mmc.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index fcbf552..b1b7e7f 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -1279,7 +1279,6 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
const struct dw_mci_drv_data *drv_data = host->drv_data;
u32 uhs;
u32 v18 = SDMMC_UHS_18V << slot->id;
- int min_uv, max_uv;
int ret;
if (drv_data && drv_data->switch_voltage)
@@ -1291,22 +1290,18 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
* does no harm but you need to set the regulator directly. Try both.
*/
uhs = mci_readl(host, UHS_REG);
- if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330) {
- min_uv = 2700000;
- max_uv = 3600000;
+ if (ios->signal_voltage == MMC_SIGNAL_VOLTAGE_330)
uhs &= ~v18;
- } else {
- min_uv = 1700000;
- max_uv = 1950000;
+ else
uhs |= v18;
- }
+
if (!IS_ERR(mmc->supply.vqmmc)) {
- ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv);
+ ret = mmc_regulator_set_vqmmc(mmc, ios);
if (ret) {
dev_dbg(&mmc->class_dev,
- "Regulator set error %d: %d - %d\n",
- ret, min_uv, max_uv);
+ "Regulator set error %d - %s V\n",
+ ret, uhs & v18 ? "1.8" : "3.3");
return ret;
}
}
--
2.6.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 4/7] mmc: dw_mmc-rockchip: dt-binding: Add tuning related things
2015-10-12 12:48 [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Heiko Stuebner
` (2 preceding siblings ...)
2015-10-12 12:48 ` [PATCH v3 3/7] mmc: dw_mmc: Use mmc_regulator_set_vqmmc in start_signal_voltage_switch Heiko Stuebner
@ 2015-10-12 12:48 ` Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 5/7] mmc: dw_mmc-rockchip: MMC tuning with the clock phase framework Heiko Stuebner
` (3 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Heiko Stuebner @ 2015-10-12 12:48 UTC (permalink / raw)
To: ulf.hansson
Cc: jh80.chung, linux-mmc, linux-arm-kernel, linux-rockchip, dianders,
amstan, Heiko Stuebner
From: Alexandru M Stan <amstan@chromium.org>
Add ciu_drive, ciu_sample clocks and default-sample-phase. This will later
be used by tuning code.
We do not touch ciu_drive (and by extension define default-drive-phase).
Drive phase is mostly used to define minimum hold times, while one could
write some code to determine what phase meets the minimum hold time
(ex 10 degrees) this will not work with the current clock phase framework
(which floors angles, so we'll get 0 deg, and there's no way to know what
resolution the floors happen at). We assume that the default drive angles
set by the hardware are good enough.
Signed-off-by: Alexandru M Stan <amstan@chromium.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
index c327c2d..3dc13b6 100644
--- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
@@ -14,6 +14,19 @@ Required Properties:
before RK3288
- "rockchip,rk3288-dw-mshc": for Rockchip RK3288
+Optional Properties:
+* clocks: from common clock binding: if ciu_drive and ciu_sample are
+ specified in clock-names, should contain handles to these clocks.
+
+* clock-names: Apart from the clock-names described in synopsys-dw-mshc.txt
+ two more clocks "ciu-drive" and "ciu-sample" are supported. They are used
+ to control the clock phases, "ciu-sample" is required for tuning high-
+ speed modes.
+
+* rockchip,default-sample-phase: The default phase to set ciu_sample at
+ probing, low speeds or in case where all phases work at tuning time.
+ If not specified 0 deg will be used.
+
Example:
rkdwmmc0@12200000 {
--
2.6.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 5/7] mmc: dw_mmc-rockchip: MMC tuning with the clock phase framework
2015-10-12 12:48 [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Heiko Stuebner
` (3 preceding siblings ...)
2015-10-12 12:48 ` [PATCH v3 4/7] mmc: dw_mmc-rockchip: dt-binding: Add tuning related things Heiko Stuebner
@ 2015-10-12 12:48 ` Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 6/7] ARM: dts: rockchip: Add drive/sample clocks for rk3288 dw_mmc devices Heiko Stuebner
` (2 subsequent siblings)
7 siblings, 0 replies; 12+ messages in thread
From: Heiko Stuebner @ 2015-10-12 12:48 UTC (permalink / raw)
To: ulf.hansson
Cc: jh80.chung, linux-mmc, linux-arm-kernel, linux-rockchip, dianders,
amstan, Heiko Stuebner
From: Alexandru M Stan <amstan@chromium.org>
This algorithm will try 1 degree increments, since there's no way to tell
what resolution the underlying phase code uses. As an added bonus, doing
many tunings yields better results since some tests are run more than once
(ex: if the underlying driver uses 45 degree increments, the tuning code
will try the same angle more than once).
It will then construct a list of good phase ranges (even ranges that cross
360/0), will pick the biggest range then it will set the sample_clk to the
middle of that range.
We do not touch ciu_drive (and by extension define default-drive-phase).
Drive phase is mostly used to define minimum hold times, while one could
write some code to determine what phase meets the minimum hold time (ex 10
degrees) this will not work with the current clock phase framework (which
floors angles, so we'll get 0 deg, and there's no way to know what
resolution the floors happen at). We assume that the default drive angles
set by the hardware are good enough.
If a device has device specific code (like exynos) then that will still
take precedence, otherwise this new code will execute. If the device wants
to tune, but has no sample_clk defined we'll return EIO with an error
message.
Signed-off-by: Alexandru M Stan <amstan@chromium.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Jaehoon Chung <jh80.chung@samsung.com>
---
drivers/mmc/host/dw_mmc-rockchip.c | 162 +++++++++++++++++++++++++++++++++++++
1 file changed, 162 insertions(+)
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index bc76aa2..4b3650f 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -13,12 +13,19 @@
#include <linux/mmc/host.h>
#include <linux/mmc/dw_mmc.h>
#include <linux/of_address.h>
+#include <linux/slab.h>
#include "dw_mmc.h"
#include "dw_mmc-pltfm.h"
#define RK3288_CLKGEN_DIV 2
+struct dw_mci_rockchip_priv_data {
+ struct clk *drv_clk;
+ struct clk *sample_clk;
+ int default_sample_phase;
+};
+
static void dw_mci_rockchip_prepare_command(struct dw_mci *host, u32 *cmdr)
{
*cmdr |= SDMMC_CMD_USE_HOLD_REG;
@@ -33,6 +40,7 @@ static int dw_mci_rk3288_setup_clock(struct dw_mci *host)
static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
{
+ struct dw_mci_rockchip_priv_data *priv = host->priv;
int ret;
unsigned int cclkin;
u32 bus_hz;
@@ -66,6 +74,158 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
/* force dw_mci_setup_bus() */
host->current_speed = 0;
}
+
+ /* 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);
+}
+
+#define NUM_PHASES 360
+#define TUNING_ITERATION_TO_PHASE(i) (DIV_ROUND_UP((i) * 360, NUM_PHASES))
+
+static int dw_mci_rk3288_execute_tuning(struct dw_mci_slot *slot)
+{
+ struct dw_mci *host = slot->host;
+ struct dw_mci_rockchip_priv_data *priv = host->priv;
+ struct mmc_host *mmc = slot->mmc;
+ int ret = 0;
+ int i;
+ bool v, prev_v = 0, first_v;
+ struct range_t {
+ int start;
+ int end; /* inclusive */
+ };
+ struct range_t *ranges;
+ unsigned int range_count = 0;
+ int longest_range_len = -1;
+ int longest_range = -1;
+ int middle_phase;
+
+ if (IS_ERR(priv->sample_clk)) {
+ dev_err(host->dev, "Tuning clock (sample_clk) not defined.\n");
+ return -EIO;
+ }
+
+ ranges = kmalloc_array(NUM_PHASES / 2 + 1, sizeof(*ranges), GFP_KERNEL);
+ if (!ranges)
+ return -ENOMEM;
+
+ /* Try each phase and extract good ranges */
+ for (i = 0; i < NUM_PHASES; ) {
+ clk_set_phase(priv->sample_clk, TUNING_ITERATION_TO_PHASE(i));
+
+ v = !mmc_send_tuning(mmc);
+
+ if (i == 0)
+ first_v = v;
+
+ if ((!prev_v) && v) {
+ range_count++;
+ ranges[range_count-1].start = i;
+ }
+ if (v) {
+ ranges[range_count-1].end = i;
+ i++;
+ } else if (i == NUM_PHASES - 1) {
+ /* No extra skipping rules if we're at the end */
+ i++;
+ } else {
+ /*
+ * No need to check too close to an invalid
+ * one since testing bad phases is slow. Skip
+ * 20 degrees.
+ */
+ i += DIV_ROUND_UP(20 * NUM_PHASES, 360);
+
+ /* Always test the last one */
+ if (i >= NUM_PHASES)
+ i = NUM_PHASES - 1;
+ }
+
+ prev_v = v;
+ }
+
+ if (range_count == 0) {
+ dev_warn(host->dev, "All phases bad!");
+ ret = -EIO;
+ goto free;
+ }
+
+ /* wrap around case, merge the end points */
+ if ((range_count > 1) && first_v && v) {
+ ranges[0].start = ranges[range_count-1].start;
+ range_count--;
+ }
+
+ if (ranges[0].start == 0 && ranges[0].end == NUM_PHASES - 1) {
+ clk_set_phase(priv->sample_clk, priv->default_sample_phase);
+ dev_info(host->dev, "All phases work, using default phase %d.",
+ priv->default_sample_phase);
+ goto free;
+ }
+
+ /* Find the longest range */
+ for (i = 0; i < range_count; i++) {
+ int len = (ranges[i].end - ranges[i].start + 1);
+
+ if (len < 0)
+ len += NUM_PHASES;
+
+ if (longest_range_len < len) {
+ longest_range_len = len;
+ longest_range = i;
+ }
+
+ dev_dbg(host->dev, "Good phase range %d-%d (%d len)\n",
+ TUNING_ITERATION_TO_PHASE(ranges[i].start),
+ TUNING_ITERATION_TO_PHASE(ranges[i].end),
+ len
+ );
+ }
+
+ dev_dbg(host->dev, "Best phase range %d-%d (%d len)\n",
+ TUNING_ITERATION_TO_PHASE(ranges[longest_range].start),
+ TUNING_ITERATION_TO_PHASE(ranges[longest_range].end),
+ longest_range_len
+ );
+
+ middle_phase = ranges[longest_range].start + longest_range_len / 2;
+ middle_phase %= NUM_PHASES;
+ dev_info(host->dev, "Successfully tuned phase to %d\n",
+ TUNING_ITERATION_TO_PHASE(middle_phase));
+
+ clk_set_phase(priv->sample_clk,
+ TUNING_ITERATION_TO_PHASE(middle_phase));
+
+free:
+ kfree(ranges);
+ return ret;
+}
+
+static int dw_mci_rk3288_parse_dt(struct dw_mci *host)
+{
+ struct device_node *np = host->dev->of_node;
+ struct dw_mci_rockchip_priv_data *priv;
+
+ priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ if (of_property_read_u32(np, "rockchip,default-sample-phase",
+ &priv->default_sample_phase))
+ priv->default_sample_phase = 0;
+
+ 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");
+
+ priv->sample_clk = devm_clk_get(host->dev, "ciu-sample");
+ if (IS_ERR(priv->sample_clk))
+ dev_dbg(host->dev, "ciu_sample not available\n");
+
+ host->priv = priv;
+
+ return 0;
}
static int dw_mci_rockchip_init(struct dw_mci *host)
@@ -95,6 +255,8 @@ static const struct dw_mci_drv_data rk3288_drv_data = {
.caps = dw_mci_rk3288_dwmmc_caps,
.prepare_command = dw_mci_rockchip_prepare_command,
.set_ios = dw_mci_rk3288_set_ios,
+ .execute_tuning = dw_mci_rk3288_execute_tuning,
+ .parse_dt = dw_mci_rk3288_parse_dt,
.setup_clock = dw_mci_rk3288_setup_clock,
.init = dw_mci_rockchip_init,
};
--
2.6.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 6/7] ARM: dts: rockchip: Add drive/sample clocks for rk3288 dw_mmc devices
2015-10-12 12:48 [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Heiko Stuebner
` (4 preceding siblings ...)
2015-10-12 12:48 ` [PATCH v3 5/7] mmc: dw_mmc-rockchip: MMC tuning with the clock phase framework Heiko Stuebner
@ 2015-10-12 12:48 ` Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 7/7] ARM: dts: rockchip: add tuning related settings to veyron devices Heiko Stuebner
2015-10-16 8:25 ` [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Ulf Hansson
7 siblings, 0 replies; 12+ messages in thread
From: Heiko Stuebner @ 2015-10-12 12:48 UTC (permalink / raw)
To: ulf.hansson
Cc: jh80.chung, linux-mmc, linux-arm-kernel, linux-rockchip, dianders,
amstan, Heiko Stuebner
From: Alexandru M Stan <amstan@chromium.org>
The drive/sample clocks can be phase shifted. The drive clock
could be used in a future patch to adjust hold times. The sample
clock is used for tuning.
Signed-off-by: Alexandru M Stan <amstan@chromium.org>
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
arch/arm/boot/dts/rk3288.dtsi | 20 ++++++++++++--------
1 file changed, 12 insertions(+), 8 deletions(-)
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 27a397f6..37c5a02 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -225,8 +225,9 @@
sdmmc: dwmmc@ff0c0000 {
compatible = "rockchip,rk3288-dw-mshc";
clock-freq-min-max = <400000 150000000>;
- clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>;
- clock-names = "biu", "ciu";
+ clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>,
+ <&cru SCLK_SDMMC_DRV>, <&cru SCLK_SDMMC_SAMPLE>;
+ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
fifo-depth = <0x100>;
interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xff0c0000 0x4000>;
@@ -236,8 +237,9 @@
sdio0: dwmmc@ff0d0000 {
compatible = "rockchip,rk3288-dw-mshc";
clock-freq-min-max = <400000 150000000>;
- clocks = <&cru HCLK_SDIO0>, <&cru SCLK_SDIO0>;
- clock-names = "biu", "ciu";
+ clocks = <&cru HCLK_SDIO0>, <&cru SCLK_SDIO0>,
+ <&cru SCLK_SDIO0_DRV>, <&cru SCLK_SDIO0_SAMPLE>;
+ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
fifo-depth = <0x100>;
interrupts = <GIC_SPI 33 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xff0d0000 0x4000>;
@@ -247,8 +249,9 @@
sdio1: dwmmc@ff0e0000 {
compatible = "rockchip,rk3288-dw-mshc";
clock-freq-min-max = <400000 150000000>;
- clocks = <&cru HCLK_SDIO1>, <&cru SCLK_SDIO1>;
- clock-names = "biu", "ciu";
+ clocks = <&cru HCLK_SDIO1>, <&cru SCLK_SDIO1>,
+ <&cru SCLK_SDIO1_DRV>, <&cru SCLK_SDIO1_SAMPLE>;
+ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
fifo-depth = <0x100>;
interrupts = <GIC_SPI 34 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xff0e0000 0x4000>;
@@ -258,8 +261,9 @@
emmc: dwmmc@ff0f0000 {
compatible = "rockchip,rk3288-dw-mshc";
clock-freq-min-max = <400000 150000000>;
- clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>;
- clock-names = "biu", "ciu";
+ clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>,
+ <&cru SCLK_EMMC_DRV>, <&cru SCLK_EMMC_SAMPLE>;
+ clock-names = "biu", "ciu", "ciu-drive", "ciu-sample";
fifo-depth = <0x100>;
interrupts = <GIC_SPI 35 IRQ_TYPE_LEVEL_HIGH>;
reg = <0xff0f0000 0x4000>;
--
2.6.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* [PATCH v3 7/7] ARM: dts: rockchip: add tuning related settings to veyron devices
2015-10-12 12:48 [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Heiko Stuebner
` (5 preceding siblings ...)
2015-10-12 12:48 ` [PATCH v3 6/7] ARM: dts: rockchip: Add drive/sample clocks for rk3288 dw_mmc devices Heiko Stuebner
@ 2015-10-12 12:48 ` Heiko Stuebner
2015-10-16 8:25 ` [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Ulf Hansson
7 siblings, 0 replies; 12+ messages in thread
From: Heiko Stuebner @ 2015-10-12 12:48 UTC (permalink / raw)
To: ulf.hansson
Cc: jh80.chung, linux-mmc, linux-arm-kernel, linux-rockchip, dianders,
amstan, Heiko Stuebner
This allows the tuning code to run and use higher speeds on capable cards.
Signed-off-by: Heiko Stuebner <heiko@sntech.de>
---
arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi | 7 ++++++-
arch/arm/boot/dts/rk3288-veyron.dtsi | 6 ++++++
2 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi b/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi
index b5334ec..fec076e 100644
--- a/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi
@@ -90,7 +90,7 @@
regulators {
vccio_sd: LDO_REG4 {
regulator-name = "vccio_sd";
- regulator-min-microvolt = <3300000>;
+ regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-state-mem {
regulator-off-in-suspend;
@@ -116,7 +116,12 @@
cap-sd-highspeed;
card-detect-delay = <200>;
cd-gpios = <&gpio7 5 GPIO_ACTIVE_LOW>;
+ rockchip,default-sample-phase = <90>;
num-slots = <1>;
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-sdr104;
vmmc-supply = <&vcc33_sd>;
vqmmc-supply = <&vccio_sd>;
};
diff --git a/arch/arm/boot/dts/rk3288-veyron.dtsi b/arch/arm/boot/dts/rk3288-veyron.dtsi
index 6820977..04c3d2a 100644
--- a/arch/arm/boot/dts/rk3288-veyron.dtsi
+++ b/arch/arm/boot/dts/rk3288-veyron.dtsi
@@ -196,7 +196,9 @@
broken-cd;
bus-width = <8>;
cap-mmc-highspeed;
+ rockchip,default-sample-phase = <158>;
disable-wp;
+ mmc-hs200-1_8v;
mmc-pwrseq = <&emmc_pwrseq>;
non-removable;
num-slots = <1>;
@@ -413,6 +415,10 @@
num-slots = <1>;
pinctrl-names = "default";
pinctrl-0 = <&sdio0_clk &sdio0_cmd &sdio0_bus4>;
+ sd-uhs-sdr12;
+ sd-uhs-sdr25;
+ sd-uhs-sdr50;
+ sd-uhs-sdr104;
vmmc-supply = <&vcc33_sys>;
vqmmc-supply = <&vcc18_wl>;
};
--
2.6.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/7] mmc: core: move ocr-bit to voltage translation into separate function
2015-10-12 12:48 ` [PATCH v3 1/7] mmc: core: move ocr-bit to voltage translation into separate function Heiko Stuebner
@ 2015-10-12 13:26 ` kbuild test robot
2015-10-12 13:44 ` Heiko Stübner
[not found] ` <1444654110-32293-2-git-send-email-heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
1 sibling, 1 reply; 12+ messages in thread
From: kbuild test robot @ 2015-10-12 13:26 UTC (permalink / raw)
Cc: kbuild-all, ulf.hansson, jh80.chung, linux-mmc, linux-arm-kernel,
linux-rockchip, dianders, amstan, Heiko Stuebner
[-- Attachment #1: Type: text/plain, Size: 1703 bytes --]
Hi Heiko,
[auto build test WARNING on rockchip/for-next -- if it's inappropriate base, please suggest rules for selecting the more suitable base]
url: https://github.com/0day-ci/linux/commits/Heiko-Stuebner/mmc-dw_mmc-rockchip-allow-tuning-using-the-clk-phase-api/20151012-205613
config: x86_64-randconfig-x011-10121751 (attached as .config)
reproduce:
# save the attached .config to linux build tree
make ARCH=x86_64
All warnings (new ones prefixed by >>):
>> drivers/mmc/core/core.c:1277:12: warning: 'mmc_ocrbitnum_to_vdd' defined but not used [-Wunused-function]
static int mmc_ocrbitnum_to_vdd(int vdd_bit, int *min_uV, int *max_uV)
^
vim +/mmc_ocrbitnum_to_vdd +1277 drivers/mmc/core/core.c
1261 while (vdd_max >= vdd_min)
1262 mask |= 1 << vdd_max--;
1263
1264 return mask;
1265 }
1266 EXPORT_SYMBOL(mmc_vddrange_to_ocrmask);
1267
1268 /**
1269 * mmc_ocrbitnum_to_vdd - Convert a OCR bit number to its voltage
1270 * @vdd_bit: OCR bit number
1271 * @min_uV: minimum voltage value (mV)
1272 * @max_uV: maximum voltage value (mV)
1273 *
1274 * This function returns the voltage range according to the provided OCR
1275 * bit number. If conversion is not possible a negative errno value returned.
1276 */
> 1277 static int mmc_ocrbitnum_to_vdd(int vdd_bit, int *min_uV, int *max_uV)
1278 {
1279 int tmp;
1280
1281 if (!vdd_bit)
1282 return -EINVAL;
1283
1284 /*
1285 * REVISIT mmc_vddrange_to_ocrmask() may have set some
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/octet-stream, Size: 22001 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH v3 1/7] mmc: core: move ocr-bit to voltage translation into separate function
2015-10-12 13:26 ` kbuild test robot
@ 2015-10-12 13:44 ` Heiko Stübner
0 siblings, 0 replies; 12+ messages in thread
From: Heiko Stübner @ 2015-10-12 13:44 UTC (permalink / raw)
To: kbuild test robot
Cc: kbuild-all, ulf.hansson, jh80.chung, linux-mmc, linux-arm-kernel,
linux-rockchip, dianders, amstan
Hi,
Am Montag, 12. Oktober 2015, 21:26:04 schrieb kbuild test robot:
> [auto build test WARNING on rockchip/for-next -- if it's inappropriate base,
> please suggest rules for selecting the more suitable base]
>
> url:
> https://github.com/0day-ci/linux/commits/Heiko-Stuebner/mmc-dw_mmc-rockchip
> -allow-tuning-using-the-clk-phase-api/20151012-205613 config:
> x86_64-randconfig-x011-10121751 (attached as .config)
> reproduce:
> # save the attached .config to linux build tree
> make ARCH=x86_64
>
> All warnings (new ones prefixed by >>):
> >> drivers/mmc/core/core.c:1277:12: warning: 'mmc_ocrbitnum_to_vdd' defined
> >> but not used [-Wunused-function]
> static int mmc_ocrbitnum_to_vdd(int vdd_bit, int *min_uV, int *max_uV)
> ^
I'm not 100% sure I understand that warning. Is it just because we're ignoring
the return value in the current first user of the function? [Which is done,
because we already tested for the vdd_bit != 0 just before invoking
mmc_ocrbitnum_to_vdd .
The second user added in the following patch then checks the return value. So
I guess this should stay as it is? I guess Ulf's call - maybe he wants it
differently anyway ;-) .
Heiko
^ permalink raw reply [flat|nested] 12+ messages in thread
* [PATCH v3.1 1/7] mmc: core: move ocr-bit to voltage translation into separate function
[not found] ` <1444654110-32293-2-git-send-email-heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
@ 2015-10-12 16:00 ` Heiko Stübner
0 siblings, 0 replies; 12+ messages in thread
From: Heiko Stübner @ 2015-10-12 16:00 UTC (permalink / raw)
To: ulf.hansson-QSEj5FYQhm4dnm+yROfE0A
Cc: amstan-F7+t8E8rja9g9hUCZPvPmw, linux-mmc-u79uwXL29TY76Z2rM5mHXA,
dianders-F7+t8E8rja9g9hUCZPvPmw,
jh80.chung-Sze3O3UU22JBDgjK7y7TUQ,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
We will shortly need the calculation of an ocr-bit to the actual
voltage in a second place too, so move it from mmc_regulator_set_ocr
to a common function mmc_ocrbitnum_to_vdd to make that possible.
Signed-off-by: Heiko Stuebner <heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
---
changes since v3:
- move mmc_ocrbitnum_to_vdd under the CONFIG_REGULATOR ifdef
Both the current as well as the new user in the followup patch are
limited to CONFIG_REGULATOR, so limit this new function as well.
I saw the mistake after Doug thankfully pointed out the CONFIG_REGULATOR issue.
drivers/mmc/core/core.c | 51 +++++++++++++++++++++++++++++++++----------------
1 file changed, 35 insertions(+), 16 deletions(-)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index 0520064..d3ffc49 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -1339,6 +1339,40 @@ struct device_node *mmc_of_find_child_device(struct mmc_host *host,
#ifdef CONFIG_REGULATOR
/**
+ * mmc_ocrbitnum_to_vdd - Convert a OCR bit number to its voltage
+ * @vdd_bit: OCR bit number
+ * @min_uV: minimum voltage value (mV)
+ * @max_uV: maximum voltage value (mV)
+ *
+ * This function returns the voltage range according to the provided OCR
+ * bit number. If conversion is not possible a negative errno value returned.
+ */
+static int mmc_ocrbitnum_to_vdd(int vdd_bit, int *min_uV, int *max_uV)
+{
+ int tmp;
+
+ if (!vdd_bit)
+ return -EINVAL;
+
+ /*
+ * REVISIT mmc_vddrange_to_ocrmask() may have set some
+ * bits this regulator doesn't quite support ... don't
+ * be too picky, most cards and regulators are OK with
+ * a 0.1V range goof (it's a small error percentage).
+ */
+ tmp = vdd_bit - ilog2(MMC_VDD_165_195);
+ if (tmp == 0) {
+ *min_uV = 1650 * 1000;
+ *max_uV = 1950 * 1000;
+ } else {
+ *min_uV = 1900 * 1000 + tmp * 100 * 1000;
+ *max_uV = *min_uV + 100 * 1000;
+ }
+
+ return 0;
+}
+
+/**
* mmc_regulator_get_ocrmask - return mask of supported voltages
* @supply: regulator to use
*
@@ -1401,22 +1435,7 @@ int mmc_regulator_set_ocr(struct mmc_host *mmc,
int min_uV, max_uV;
if (vdd_bit) {
- int tmp;
-
- /*
- * REVISIT mmc_vddrange_to_ocrmask() may have set some
- * bits this regulator doesn't quite support ... don't
- * be too picky, most cards and regulators are OK with
- * a 0.1V range goof (it's a small error percentage).
- */
- tmp = vdd_bit - ilog2(MMC_VDD_165_195);
- if (tmp == 0) {
- min_uV = 1650 * 1000;
- max_uV = 1950 * 1000;
- } else {
- min_uV = 1900 * 1000 + tmp * 100 * 1000;
- max_uV = min_uV + 100 * 1000;
- }
+ mmc_ocrbitnum_to_vdd(vdd_bit, &min_uV, &max_uV);
result = regulator_set_voltage(supply, min_uV, max_uV);
if (result == 0 && !mmc->regulator_enabled) {
--
2.6.1
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api
2015-10-12 12:48 [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Heiko Stuebner
` (6 preceding siblings ...)
2015-10-12 12:48 ` [PATCH v3 7/7] ARM: dts: rockchip: add tuning related settings to veyron devices Heiko Stuebner
@ 2015-10-16 8:25 ` Ulf Hansson
7 siblings, 0 replies; 12+ messages in thread
From: Ulf Hansson @ 2015-10-16 8:25 UTC (permalink / raw)
To: Heiko Stuebner
Cc: Jaehoon Chung, linux-mmc, linux-arm-kernel@lists.infradead.org,
open list:ARM/Rockchip SoC..., Doug Anderson, Alexandru Stan
On 12 October 2015 at 14:48, Heiko Stuebner <heiko@sntech.de> wrote:
> This series resurrects and adapts some individual patches whose sum
> enable the dw_mmc hosts on Rockchip socs to tune clock phases using
> the generic phase api (rk3288 and following have this capability).
>
> The changes to the original mmc-phase clocks are expanded by further
> findings resulting from devices being used in the field.
>
> Similarly the regulator handling changes do use the brand new
> regulator_set_voltage_triplet call to allow specifying lower and upper
> limits. One possible point of discussion are the two voltage ranges
> that are tried for the 3.3V signal level. Trying to stay near vmmc
> at first and only then opening the range to the full 2.7-3.6V.
>
> This mainly circumvents a shortcoming of the regulator voltage
> setting, in that even with regulator_set_voltage_triplet the regulator
> framework will take the lowest possible voltage when the possible
> voltages are below the target voltage. While it may be ideal to solve
> this on the regulator side, I'm not seeing this appearing in the short
> term, mainly because all regulator parts (including regulator drivers)
> are keyed to selecting the lowest voltage from the range, while on the
> mmc side we know which voltages may work and trying this in two steps
> does not create to much overhead, as unsupported voltages are already
> filtered out by the regulator_is_voltage_selected calls.
>
> changes since v2:
> - use host->ios.vdd to read vmmc from instead of requiring the vmmc
> regulator. Suggested by Ulf this makes the voltage setting still work
> even if only the vqmmc but not the vmmc regulator is supplied.
> - add Acks from Jaehoon Chung to the dw_mmc parts
> - drop first two clock patches that already got applied to the mmc tree
>
> changes since v1:
> - address comment from Jaehoon Chung and keep this local to Rockchip
> for the time being
> - address comments from Ulf and Doug in making it more explicit
> that the two-step 3.3V voltage setting essentially works around
> a limitation of regulator_set_voltage_triplet
>
> Alexandru M Stan (3):
> mmc: dw_mmc-rockchip: dt-binding: Add tuning related things
> mmc: dw_mmc-rockchip: MMC tuning with the clock phase framework
> ARM: dts: rockchip: Add drive/sample clocks for rk3288 dw_mmc devices
>
> Douglas Anderson (2):
> mmc: core: Add mmc_regulator_set_vqmmc()
> mmc: dw_mmc: Use mmc_regulator_set_vqmmc in
> start_signal_voltage_switch
>
> Heiko Stuebner (2):
> mmc: core: move ocr-bit to voltage translation into separate function
> ARM: dts: rockchip: add tuning related settings to veyron devices
>
> .../devicetree/bindings/mmc/rockchip-dw-mshc.txt | 13 ++
> arch/arm/boot/dts/rk3288-veyron-sdmmc.dtsi | 7 +-
> arch/arm/boot/dts/rk3288-veyron.dtsi | 6 +
> arch/arm/boot/dts/rk3288.dtsi | 20 ++-
> drivers/mmc/core/core.c | 129 ++++++++++++++--
> drivers/mmc/host/dw_mmc-rockchip.c | 162 +++++++++++++++++++++
> drivers/mmc/host/dw_mmc.c | 17 +--
> include/linux/mmc/host.h | 7 +
> 8 files changed, 325 insertions(+), 36 deletions(-)
>
> --
> 2.6.1
>
Thanks, applied for next (with v3.1 of patch1)!
Kind regards
Uffe
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2015-10-16 8:25 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-10-12 12:48 [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 1/7] mmc: core: move ocr-bit to voltage translation into separate function Heiko Stuebner
2015-10-12 13:26 ` kbuild test robot
2015-10-12 13:44 ` Heiko Stübner
[not found] ` <1444654110-32293-2-git-send-email-heiko-4mtYJXux2i+zQB+pC5nmwQ@public.gmane.org>
2015-10-12 16:00 ` [PATCH v3.1 " Heiko Stübner
2015-10-12 12:48 ` [PATCH v3 2/7] mmc: core: Add mmc_regulator_set_vqmmc() Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 3/7] mmc: dw_mmc: Use mmc_regulator_set_vqmmc in start_signal_voltage_switch Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 4/7] mmc: dw_mmc-rockchip: dt-binding: Add tuning related things Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 5/7] mmc: dw_mmc-rockchip: MMC tuning with the clock phase framework Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 6/7] ARM: dts: rockchip: Add drive/sample clocks for rk3288 dw_mmc devices Heiko Stuebner
2015-10-12 12:48 ` [PATCH v3 7/7] ARM: dts: rockchip: add tuning related settings to veyron devices Heiko Stuebner
2015-10-16 8:25 ` [PATCH v3 0/7] mmc: dw_mmc-rockchip: allow tuning using the clk-phase api Ulf Hansson
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).