* Re: [PATCH v7 11/14] mmc: sdhci-msm: Add HS400 platform support
From: Ulf Hansson @ 2016-11-14 15:44 UTC (permalink / raw)
To: kbuild test robot
Cc: Ritesh Harjani, kbuild-all@01.org, linux-mmc, Adrian Hunter,
Shawn Lin, Stephen Boyd, Andy Gross, devicetree@vger.kernel.org,
linux-clk, david.brown, linux-arm-msm@vger.kernel.org,
Georgi Djakov, Alex Lemberg, Mateusz Nowak, Yuliy Izrailov,
Asutosh Das, kdorfman@codeaurora.org, David Griego
In-Reply-To: <201611142112.EdLY7cAN%fengguang.wu@intel.com>
Hi,
On 14 November 2016 at 14:53, kbuild test robot <lkp@intel.com> wrote:
> Hi Venkat,
>
> [auto build test ERROR on ulf.hansson-mmc/next]
> [also build test ERROR on v4.9-rc5]
> [cannot apply to next-20161114]
> [if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
Here we go...
>
> url: https://github.com/0day-ci/linux/commits/Ritesh-Harjani/mmc-sdhci-msm-Add-clk-rates-DDR-HS400-support/20161114-142815
> base: https://git.linaro.org/people/ulf.hansson/mmc next
This above is the old tree, here's the new:
git://git.kernel.org/pub/scm/linux/kernel/git/ulfh/mmc.git
Could you please update the path in the build system?
[...]
Kind regards
Ulf Hansson
^ permalink raw reply
* [PATCH v3] mmc: sdhci-of-esdhc: fixup PRESENT_STATE read
From: Michael Walle @ 2016-11-14 15:12 UTC (permalink / raw)
To: linux-kernel
Cc: linux-mmc, Ulf Hansson, Adrian Hunter, yangbo lu, Michael Walle
Since commit 87a18a6a5652 ("mmc: mmc: Use ->card_busy() to detect busy
cards in __mmc_switch()") the ESDHC driver is broken:
mmc0: Card stuck in programming state! __mmc_switch
mmc0: error -110 whilst initialising MMC card
Since this commit __mmc_switch() uses ->card_busy(), which is
sdhci_card_busy() for the esdhc driver. sdhci_card_busy() uses the
PRESENT_STATE register, specifically the DAT0 signal level bit. But the
ESDHC uses a non-conformant PRESENT_STATE register, thus a read fixup is
required to make the driver work again.
Signed-off-by: Michael Walle <michael@walle.cc>
Fixes: 87a18a6a5652 ("mmc: mmc: Use ->card_busy() to detect busy cards in __mmc_switch()")
---
v3:
- explain the bits in the comments
- use bits[19:0] from the original value, all other will be taken from the
fixup value.
v2:
- use lower bits of the original value (that was actually a typo)
- add fixes tag
- fix typo
drivers/mmc/host/sdhci-of-esdhc.c | 13 +++++++++++++
1 file changed, 13 insertions(+)
diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-of-esdhc.c
index fb71c86..74cf3b1 100644
--- a/drivers/mmc/host/sdhci-of-esdhc.c
+++ b/drivers/mmc/host/sdhci-of-esdhc.c
@@ -66,6 +66,19 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host,
return ret;
}
}
+ /*
+ * The DAT[3:0] line signal levels and the CMD line signal level are
+ * not compatible with standard SDHC register. The line signal levels
+ * DAT[7:0] are at bits 31:24 and the line signal level is at bit 23.
+ * All other bits are the same as in the standard SDHC register.
+ */
+ if (spec_reg == SDHCI_PRESENT_STATE) {
+ ret = value & 0x000fffff;
+ ret |= (value >> 4) & SDHCI_DATA_LVL_MASK;
+ ret |= (value << 1) & 0x01000000;
+ return ret;
+ }
+
ret = value;
return ret;
}
--
2.1.4
^ permalink raw reply related
* Re: [PATCH v7 11/14] mmc: sdhci-msm: Add HS400 platform support
From: kbuild test robot @ 2016-11-14 13:53 UTC (permalink / raw)
Cc: kbuild-all-JC7UmRfGjtg, ulf.hansson-QSEj5FYQhm4dnm+yROfE0A,
linux-mmc-u79uwXL29TY76Z2rM5mHXA,
adrian.hunter-ral2JQCrhuEAvxtiuMwx3w,
shawn.lin-TNX95d0MmH7DzftRWevZcw, sboyd-sgV2jX0FEOL9JmXXK+q4OQ,
andy.gross-QSEj5FYQhm4dnm+yROfE0A,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-clk-u79uwXL29TY76Z2rM5mHXA,
david.brown-QSEj5FYQhm4dnm+yROfE0A,
linux-arm-msm-u79uwXL29TY76Z2rM5mHXA,
georgi.djakov-QSEj5FYQhm4dnm+yROfE0A,
alex.lemberg-XdAiOPVOjttBDgjK7y7TUQ,
mateusz.nowak-ral2JQCrhuEAvxtiuMwx3w,
Yuliy.Izrailov-XdAiOPVOjttBDgjK7y7TUQ,
asutoshd-sgV2jX0FEOL9JmXXK+q4OQ, kdorfman-sgV2jX0FEOL9JmXXK+q4OQ,
david.griego-QSEj5FYQhm4dnm+yROfE0A,
stummala-sgV2jX0FEOL9JmXXK+q4OQ, venkatg-sgV2jX0FEOL9JmXXK+q4OQ,
rnayak-sgV2jX0FEOL9JmXXK+q4OQ,
pramod.gurav-QSEj5FYQhm4dnm+yROfE0A, Ritesh Harjani
In-Reply-To: <1479103248-9491-12-git-send-email-riteshh-sgV2jX0FEOL9JmXXK+q4OQ@public.gmane.org>
[-- Attachment #1: Type: text/plain, Size: 1791 bytes --]
Hi Venkat,
[auto build test ERROR on ulf.hansson-mmc/next]
[also build test ERROR on v4.9-rc5]
[cannot apply to next-20161114]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/Ritesh-Harjani/mmc-sdhci-msm-Add-clk-rates-DDR-HS400-support/20161114-142815
base: https://git.linaro.org/people/ulf.hansson/mmc next
config: arm-defconfig (attached as .config)
compiler: arm-linux-gnueabi-gcc (Debian 6.1.1-9) 6.1.1 20160705
reproduce:
wget https://git.kernel.org/cgit/linux/kernel/git/wfg/lkp-tests.git/plain/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# save the attached .config to linux build tree
make.cross ARCH=arm
Note: the linux-review/Ritesh-Harjani/mmc-sdhci-msm-Add-clk-rates-DDR-HS400-support/20161114-142815 HEAD baef00575b049e246cebd910c417f34cada20ee0 builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
drivers/mmc/host/sdhci-msm.c: In function 'sdhci_msm_execute_tuning':
>> drivers/mmc/host/sdhci-msm.c:498:3: error: 'msm_host' undeclared (first use in this function)
msm_host->tuning_done = true;
^~~~~~~~
drivers/mmc/host/sdhci-msm.c:498:3: note: each undeclared identifier is reported only once for each function it appears in
vim +/msm_host +498 drivers/mmc/host/sdhci-msm.c
492 dev_dbg(mmc_dev(mmc), "%s: No tuning point found\n",
493 mmc_hostname(mmc));
494 rc = -EIO;
495 }
496
497 if (!rc)
> 498 msm_host->tuning_done = true;
499 return rc;
500 }
501
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 39300 bytes --]
^ permalink raw reply
* Re: [PATCH 2/2] mmc: sdhci-pci: Add support for HS200 tuning mode on AMD, eMMC-4.5.1
From: Adrian Hunter @ 2016-11-14 13:37 UTC (permalink / raw)
To: Shyam Sundar S K
Cc: Ulf Hansson, linux-mmc, Sen, Pankaj, Agrawal, Nitesh-kumar,
Shah, Nehal-bakulchandra
In-Reply-To: <dbebff7a-d144-9dc5-6e59-3a39274ee21d@amd.com>
On 14/11/16 08:38, Shyam Sundar S K wrote:
>
>
> On 11/11/2016 6:11 PM, Adrian Hunter wrote:
>> On 10/11/16 14:51, Shyam Sundar S K wrote:
>>> This patch adds support for HS200 tuning mode on AMD eMMC-4.5.1
>>>
>>> Reviewed-by: Sen, Pankaj <Pankaj.Sen@amd.com>
>>> Reviewed-by: Shah, Nehal-bakulchandra <Nehal-bakulchandra.Shah@amd.com>
>>> Signed-off-by: S-k, Shyam-sundar <Shyam-sundar.S-k@amd.com>
>>> ---
>>> drivers/mmc/host/sdhci-pci-core.c | 178 +++++++++++++++++++++++++++++++++++++-
>>> 1 file changed, 177 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/drivers/mmc/host/sdhci-pci-core.c b/drivers/mmc/host/sdhci-pci-core.c
>>> index 782c8d2..9576f82 100644
>>> --- a/drivers/mmc/host/sdhci-pci-core.c
>>> +++ b/drivers/mmc/host/sdhci-pci-core.c
>>> @@ -817,6 +817,171 @@ enum amd_chipset_gen {
>>> AMD_CHIPSET_UNKNOWN,
>>> };
>>>
>>> +static const struct sdhci_ops amd_sdhci_pci_ops;
>>> +
>>> +struct amd_tuning_descriptor {
>>> + u8 tune_around;
>>> + bool this_tune_ok;
>>> + bool last_tune_ok;
>>> + u8 valid_front;
>>> + u8 valid_window_max;
>>> + u8 tune_low_max;
>>> + u8 tune_low;
>>> + u8 valid_window;
>>> + u8 tune_result;
>>> +};
>>> +
>>> +static int amd_tuning_reset(struct sdhci_host *host)
>>> +{
>>> + unsigned int val;
>>> + unsigned long flags;
>>> +
>>> + spin_lock_irqsave(&host->lock, flags);
>>> +
>>> + val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>>> + val |= SDHCI_CTRL_PRESET_VAL_ENABLE | SDHCI_CTRL_EXEC_TUNING;
>>> + sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
>>> +
>>> + val = sdhci_readw(host, SDHCI_HOST_CONTROL2);
>>> + val &= ~SDHCI_CTRL_EXEC_TUNING;
>>> + sdhci_writew(host, val, SDHCI_HOST_CONTROL2);
>>> +
>>> + spin_unlock_irqrestore(&host->lock, flags);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int amd_config_tuning_phase(struct sdhci_host *host, u8 phase)
>>> +{
>>> + struct sdhci_pci_slot *slot = sdhci_priv(host);
>>> + struct pci_dev *pdev = slot->chip->pdev;
>>> + unsigned int val;
>>> + unsigned long flags;
>>> +
>>> + spin_lock_irqsave(&host->lock, flags);
>>> +
>>> + pci_read_config_dword(pdev, 0xb8, &val);
>>> + val &= ~0x1f;
>>> + val |= (0x10800 | (phase << 1));
>>> + pci_write_config_dword(pdev, 0xb8, val);
>>> +
>>> + spin_unlock_irqrestore(&host->lock, flags);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int amd_find_good_phase(struct sdhci_host *host)
>>> +{
>>> + struct sdhci_pci_slot *slot = sdhci_priv(host);
>>> + struct pci_dev *pdev = slot->chip->pdev;
>>> + struct amd_tuning_descriptor *td = sdhci_pci_priv(slot);
>>> +
>>> + unsigned int val;
>>> + unsigned long flags;
>>> +
>>> + spin_lock_irqsave(&host->lock, flags);
>>> +
>>> + if (td->this_tune_ok)
>>> + td->valid_front += 1;
>>> + if ((!td->this_tune_ok && td->last_tune_ok) ||
>>> + (td->tune_around == 11)) {
>>> + if (td->valid_window > td->valid_window_max) {
>>> + td->valid_window_max = td->valid_window;
>>> + td->tune_low_max = td->tune_low;
>>> + }
>>> + }
>>> + if (td->this_tune_ok && (!td->last_tune_ok))
>>> + td->tune_low = td->tune_around;
>>> + if (!td->this_tune_ok && td->last_tune_ok)
>>> + td->valid_window = 0;
>>> + else if (td->this_tune_ok)
>>> + td->valid_window += 1;
>>> +
>>> + td->last_tune_ok = td->this_tune_ok;
>>> +
>>> + if (td->tune_around == 11) {
>>> + if ((td->valid_front + td->valid_window) >
>>> + td->valid_window_max) {
>>> + if (td->valid_front > td->valid_window)
>>> + td->tune_result = ((td->valid_front -
>>> + td->valid_window) >> 1);
>>> + else
>>> + td->tune_result = td->tune_low +
>>> + ((td->valid_window + td->valid_front) >> 1);
>>> + } else {
>>> + td->tune_result = td->tune_low_max +
>>> + (td->valid_window_max >> 1);
>>> + }
>>> +
>>> + if (td->tune_result > 0x0b)
>>> + td->tune_result = 0x0b;
>>> +
>>> + pci_read_config_dword(pdev, 0xb8, &val);
>>> + val &= ~0x1f;
>>> + val |= (0x10800 | (td->tune_result << 1));
>>> + pci_write_config_dword(pdev, 0xb8, val);
>>> + }
>>> +
>>> + spin_unlock_irqrestore(&host->lock, flags);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int amd_enable_manual_tuning(struct sdhci_pci_slot *slot)
>>> +{
>>> + struct pci_dev *pdev = slot->chip->pdev;
>>> + unsigned int val;
>>> +
>>> + pci_read_config_dword(pdev, 0xd0, &val);
>>> + val &= 0xffffffcf;
>>> + val |= 0x30;
>>> + pci_write_config_dword(pdev, 0xd0, val);
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int amd_execute_tuning(struct sdhci_host *host, u32 opcode)
>>> +{
>>> + struct sdhci_pci_slot *slot = sdhci_priv(host);
>>> + struct amd_tuning_descriptor *td = sdhci_pci_priv(slot);
>>> + u8 ctrl;
>>> +
>>> + amd_tuning_reset(host);
>>> + memset(td, 0, sizeof(struct amd_tuning_descriptor));
>>
>> I didn't notice last time that you are always clearing all the values in the
>> tuning descriptor, so it doesn't need to be kept between calls to
>> amd_execute_tuning(). So it should be a local variable that you pass to the
>> functions that need it. Then you don't need the patch I sent at all.
>>
>> Does that make sense?
>>
>
> Hi Adrian,
>
> Thanks for pointing this out. Your patch will help, so will remove the memset()
> and redo the submission. Is this OK ?
Sure
^ permalink raw reply
* [PATCH v2 01/10] dt-bindings: rockchip-dw-mshc: add RK1108 dw-mshc description
From: Andy Yan @ 2016-11-14 12:01 UTC (permalink / raw)
To: heiko-4mtYJXux2i+zQB+pC5nmwQ
Cc: mark.rutland-5wv7dgnIgG8, devicetree-u79uwXL29TY76Z2rM5mHXA,
ulf.hansson-QSEj5FYQhm4dnm+yROfE0A,
shawn.lin-TNX95d0MmH7DzftRWevZcw,
linux-mmc-u79uwXL29TY76Z2rM5mHXA,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
linux-rockchip-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
robh+dt-DgEjT+Ai2ygdnm+yROfE0A
In-Reply-To: <1479124550-24037-1-git-send-email-andy.yan-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
From: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
Add "rockchip,rk1108-dw-mshc", "rockchip,rk3288-dw-mshc" for
dwmmc on rk1108 platform.
Signed-off-by: Shawn Lin <shawn.lin-TNX95d0MmH7DzftRWevZcw@public.gmane.org>
---
Changes in v2: None
Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
index 07184e8..ea9c1c9 100644
--- a/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/rockchip-dw-mshc.txt
@@ -13,6 +13,7 @@ Required Properties:
- "rockchip,rk2928-dw-mshc": for Rockchip RK2928 and following,
before RK3288
- "rockchip,rk3288-dw-mshc": for Rockchip RK3288
+ - "rockchip,rk1108-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK1108
- "rockchip,rk3036-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3036
- "rockchip,rk3368-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3368
- "rockchip,rk3399-dw-mshc", "rockchip,rk3288-dw-mshc": for Rockchip RK3399
--
2.7.4
^ permalink raw reply related
* [PATCH v2 00/10] Add basic support for Rockchip RK1108 SOC
From: Andy Yan @ 2016-11-14 11:55 UTC (permalink / raw)
To: heiko
Cc: shawn.lin, linus.walleij, robh+dt, linux-clk, linux-rockchip,
devicetree, mturquette, sboyd, linux-gpio, linux,
linux-arm-kernel, ulf.hansson, linux-mmc, linux-kernel,
mark.rutland, Andy Yan
RK1108 is embedded with an ARM Cortex-A7 single core and a DSP core.
It is designed for varies application scenario such as car DVR, sports
DV, secure camera and UAV camera.
This patch series add basic support for it, which can boot a board with
initramfs into shell.
More new feathers will come soon.
Changes in v2:
- split dt-binding header from clk driver
- fix some CodingStyle issues
- add dt-binding documentation for pinctrl
- add pull and drive-strength functionality for pinctrl
- fix timer and gic dt description
- ordering devices by register address
- move the board in the rockchip.txt to the block of Rockchip boards
Andy Yan (6):
dt-bindings: add documentation for rk1108 pinctrl
pinctrl: rockchip: add support for rk1108
ARM: add low level debug uart for rk1108
ARM: dts: add basic support for Rockchip RK1108 SOC
ARM: rockchip: enable support for RK1108 SoC
ARM: dts: rockchip: add rockchip RK1108 Evaluation board
Shawn Lin (4):
dt-bindings: rockchip-dw-mshc: add RK1108 dw-mshc description
dt-bindings: add documentation for rk1108 cru
clk: rockchip: add dt-binding header for rk1108
clk: rockchip: add clock controller for rk1108
Documentation/devicetree/bindings/arm/rockchip.txt | 5 +-
.../bindings/clock/rockchip,rk1108-cru.txt | 60 +++
.../devicetree/bindings/mmc/rockchip-dw-mshc.txt | 1 +
.../bindings/pinctrl/rockchip,pinctrl.txt | 9 +-
arch/arm/Kconfig.debug | 30 ++
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/rk1108-evb.dts | 69 ++++
arch/arm/boot/dts/rk1108.dtsi | 428 +++++++++++++++++++
arch/arm/mach-rockchip/rockchip.c | 1 +
drivers/clk/rockchip/Makefile | 1 +
drivers/clk/rockchip/clk-rk1108.c | 451 +++++++++++++++++++++
drivers/clk/rockchip/clk.h | 14 +
drivers/pinctrl/pinctrl-rockchip.c | 87 +++-
include/dt-bindings/clock/rk1108-cru.h | 270 ++++++++++++
14 files changed, 1421 insertions(+), 6 deletions(-)
create mode 100644 Documentation/devicetree/bindings/clock/rockchip,rk1108-cru.txt
create mode 100644 arch/arm/boot/dts/rk1108-evb.dts
create mode 100644 arch/arm/boot/dts/rk1108.dtsi
create mode 100644 drivers/clk/rockchip/clk-rk1108.c
create mode 100644 include/dt-bindings/clock/rk1108-cru.h
--
2.7.4
^ permalink raw reply
* [patch] mmc: mmc_test: Uninitialized return value
From: Dan Carpenter @ 2016-11-14 11:31 UTC (permalink / raw)
To: Ulf Hansson, Per Forlin
Cc: Adrian Hunter, Linus Walleij, Wolfram Sang, linux-mmc,
linux-kernel, kernel-janitors
We never set "ret" to RESULT_OK.
Fixes: 9f9c4180f88d ("mmc: mmc_test: add test for non-blocking transfers")
Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index f61c812..5ba6d77 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -832,7 +832,7 @@ static int mmc_test_nonblock_transfer(struct mmc_test_card *test,
struct mmc_async_req *other_areq = &test_areq[1].areq;
enum mmc_blk_status status;
int i;
- int ret;
+ int ret = RESULT_OK;
test_areq[0].test = test;
test_areq[1].test = test;
^ permalink raw reply related
* Re: [PATCH 2/2] mmc: tmio: remove SDIO from TODO list
From: Simon Horman @ 2016-11-14 11:25 UTC (permalink / raw)
To: Wolfram Sang; +Cc: linux-mmc, linux-renesas-soc
In-Reply-To: <20161113142912.4041-3-wsa+renesas@sang-engineering.com>
On Sun, Nov 13, 2016 at 03:29:12PM +0100, Wolfram Sang wrote:
> We surely have SDIO support by now :)
>
> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
^ permalink raw reply
* Re: [PATCH 1/2] mmc: tmio: fix wrong bitmask for SDIO irqs
From: Simon Horman @ 2016-11-14 11:24 UTC (permalink / raw)
To: Wolfram Sang; +Cc: linux-mmc, linux-renesas-soc
In-Reply-To: <20161113142912.4041-2-wsa+renesas@sang-engineering.com>
On Sun, Nov 13, 2016 at 03:29:11PM +0100, Wolfram Sang wrote:
> Commit 7729c7a232a953 ("mmc: tmio: Provide separate interrupt handlers")
> refactored the sdio irq handler and wrongly used the mask for SD irqs,
> not for SDIO irqs. This doesn't really matter in practice because both
> values keep the only interrupt we are interested in. But still, this is
> wrong and wants to be fixed.
>
> Signed-off-by: Wolfram Sang <wsa+renesas@sang-engineering.com>
Reviewed-by: Simon Horman <horms+renesas@verge.net.au>
> ---
> drivers/mmc/host/tmio_mmc_pio.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/drivers/mmc/host/tmio_mmc_pio.c b/drivers/mmc/host/tmio_mmc_pio.c
> index dbc3cb14f3321b..2b04e6e87192c7 100644
> --- a/drivers/mmc/host/tmio_mmc_pio.c
> +++ b/drivers/mmc/host/tmio_mmc_pio.c
> @@ -741,7 +741,7 @@ static void tmio_mmc_sdio_irq(int irq, void *devid)
> return;
>
> status = sd_ctrl_read16(host, CTL_SDIO_STATUS);
> - ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdcard_irq_mask;
> + ireg = status & TMIO_SDIO_MASK_ALL & ~host->sdio_irq_mask;
>
> sdio_status = status & ~TMIO_SDIO_MASK_ALL;
> if (pdata->flags & TMIO_MMC_SDIO_STATUS_QUIRK)
> --
> 2.9.3
>
^ permalink raw reply
* [Patch v1] mmc: sd: update sd_bus_speed when sd card speed switch fails
From: Gao Pan @ 2016-11-14 10:33 UTC (permalink / raw)
To: linux-mmc, ulf.hansson; +Cc: pandy.gao, frank.li, fugang.duan
In sd_set_bus_speed_mode(), sd card speed is switched to sd_bus_speed.
However, the switch process may fail. When it happens, sd card is in
default speed mode, which is SDR12 as described in Spec3.0.
In such case, the sd_bus_speed should be updated according to status[16].
Signed-off-by: Gao Pan <pandy.gao@nxp.com>
Reviewed-by: Fugang Duan <B38611@freescale.com>
---
drivers/mmc/core/sd.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/mmc/core/sd.c b/drivers/mmc/core/sd.c
index 73c762a..ac456ec 100644
--- a/drivers/mmc/core/sd.c
+++ b/drivers/mmc/core/sd.c
@@ -471,9 +471,11 @@ static int sd_set_bus_speed_mode(struct mmc_card *card, u8 *status)
if (err)
return err;
- if ((status[16] & 0xF) != card->sd_bus_speed)
+ if ((status[16] & 0xF) != card->sd_bus_speed) {
+ card->sd_bus_speed = status[16] & 0xF;
pr_warn("%s: Problem setting bus speed mode!\n",
mmc_hostname(card->host));
+ }
else {
mmc_set_timing(card->host, timing);
mmc_set_clock(card->host, card->sw_caps.uhs_max_dtr);
--
1.9.1
^ permalink raw reply related
* Re: [PATCH 8/9] DT: stm32f469-disco: add node for SDIO controller
From: Alexandre Torgue @ 2016-11-14 10:42 UTC (permalink / raw)
To: andrea.merello; +Cc: Ulf Hansson, Maxime Coquelin, linux-mmc, Bruno Herrera
In-Reply-To: <CAN8YU5PKU7iP1he6MvPCOZ0pf-4fdKgBi8gWmppjdyMU9c=u5Q@mail.gmail.com>
Hi Andrea
On 11/14/2016 11:36 AM, Andrea Merello wrote:
> On Thu, Nov 10, 2016 at 11:54 AM, Alexandre Torgue
> <alexandre.torgue@st.com> wrote:
>> Hi Andrea
>>
>>
>> On 11/08/2016 02:43 PM, Andrea Merello wrote:
>>>
>>> Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
>>> ---
>>> arch/arm/boot/dts/stm32f429.dtsi | 2 +-
>>> arch/arm/boot/dts/stm32f469-disco.dts | 30 ++++++++++++++++++++++++++++++
>>> 2 files changed, 31 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/arch/arm/boot/dts/stm32f429.dtsi
>>> b/arch/arm/boot/dts/stm32f429.dtsi
>>> index d6d0548..23e6a5e 100644
>>> --- a/arch/arm/boot/dts/stm32f429.dtsi
>>> +++ b/arch/arm/boot/dts/stm32f429.dtsi
>>> @@ -185,7 +185,7 @@
>>> interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>,
>>> <10>, <23>, <40>, <41>, <42>, <62>, <76>;
>>> };
>>>
>>> - pin-controller {
>>> + pinctrl:pin-controller {
>>> #address-cells = <1>;
>>> #size-cells = <1>;
>>> compatible = "st,stm32f429-pinctrl";
>>> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts
>>> b/arch/arm/boot/dts/stm32f469-disco.dts
>>> index e911af8..e16dfc3 100644
>>> --- a/arch/arm/boot/dts/stm32f469-disco.dts
>>> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
>>> @@ -64,12 +64,42 @@
>>> aliases {
>>> serial0 = &usart3;
>>> };
>>> +
>>> + mmc_vcard: mmc_vcard {
>>> + compatible = "regulator-fixed";
>>> + regulator-name = "mmc_vcard";
>>> + regulator-min-microvolt = <3300000>;
>>> + regulator-max-microvolt = <3300000>;
>>
>> As I assume you will send a v2 (due to kbuild issue) remove empty line
>> please.
>
> Sure. I will do. (But unfortunately it will not happen very soon :( )
No pb.
>
> In the meantime comments and testing are appreciated. Also, I forgot
> to say that, if one wants to try this, he/she will need the bootloader
> to set properly the 48MHz clk for SD (for afboot use my tree -
> pull-req pending on Maxime Coquelin tree). For clk driver probably my
> patch for making it aware of the 48MHz setting is still needed (I've
> not looked into other recent clk patches yet)..
did you see patches sent by Gabriel Fernandez: "[PATCH 0/6] Add STM32F4
missing clocks". This series should add support for 48 MHz. So it is
needed to check first if Gabriel's series is enough.
Thanks
Alex
>
>>> +
>>> + };
>>> };
>>>
>>> &clk_hse {
>>> clock-frequency = <8000000>;
>>> };
>>>
>>> +&pinctrl {
>>> + sdio-cd {
>>> + sdio_cd: sdio-cd {
>>> + pins {
>>> + pinmux = <STM32F429_PG2_FUNC_GPIO>;
>>> + bias-pull-up;
>>> + };
>>> + };
>>> + };
>>> +};
>>> +
>>> +&sdio {
>>> + status = "okay";
>>> + vmmc-supply = <&mmc_vcard>;
>>> + cd-gpios = <&gpiog 2 0>;
>>> + cd-inverted;
>>> + pinctrl-names = "default", "opendrain", "cd";
>>> + pinctrl-0 = <&sdio_pins>, <&sdio_cd>;
>>> + pinctrl-1 = <&sdio_pins_od>, <&sdio_cd>;
>>> + bus-width = <4>;
>>> +};
>>> +
>>> &usart3 {
>>> status = "okay";
>>> };
>>>
>>
^ permalink raw reply
* Re: [PATCH 8/9] DT: stm32f469-disco: add node for SDIO controller
From: Andrea Merello @ 2016-11-14 10:36 UTC (permalink / raw)
To: Alexandre Torgue; +Cc: Ulf Hansson, Maxime Coquelin, linux-mmc, Bruno Herrera
In-Reply-To: <ffdc246c-0197-f1a7-f848-a02b4e7df13c@st.com>
On Thu, Nov 10, 2016 at 11:54 AM, Alexandre Torgue
<alexandre.torgue@st.com> wrote:
> Hi Andrea
>
>
> On 11/08/2016 02:43 PM, Andrea Merello wrote:
>>
>> Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
>> ---
>> arch/arm/boot/dts/stm32f429.dtsi | 2 +-
>> arch/arm/boot/dts/stm32f469-disco.dts | 30 ++++++++++++++++++++++++++++++
>> 2 files changed, 31 insertions(+), 1 deletion(-)
>>
>> diff --git a/arch/arm/boot/dts/stm32f429.dtsi
>> b/arch/arm/boot/dts/stm32f429.dtsi
>> index d6d0548..23e6a5e 100644
>> --- a/arch/arm/boot/dts/stm32f429.dtsi
>> +++ b/arch/arm/boot/dts/stm32f429.dtsi
>> @@ -185,7 +185,7 @@
>> interrupts = <1>, <2>, <3>, <6>, <7>, <8>, <9>,
>> <10>, <23>, <40>, <41>, <42>, <62>, <76>;
>> };
>>
>> - pin-controller {
>> + pinctrl:pin-controller {
>> #address-cells = <1>;
>> #size-cells = <1>;
>> compatible = "st,stm32f429-pinctrl";
>> diff --git a/arch/arm/boot/dts/stm32f469-disco.dts
>> b/arch/arm/boot/dts/stm32f469-disco.dts
>> index e911af8..e16dfc3 100644
>> --- a/arch/arm/boot/dts/stm32f469-disco.dts
>> +++ b/arch/arm/boot/dts/stm32f469-disco.dts
>> @@ -64,12 +64,42 @@
>> aliases {
>> serial0 = &usart3;
>> };
>> +
>> + mmc_vcard: mmc_vcard {
>> + compatible = "regulator-fixed";
>> + regulator-name = "mmc_vcard";
>> + regulator-min-microvolt = <3300000>;
>> + regulator-max-microvolt = <3300000>;
>
> As I assume you will send a v2 (due to kbuild issue) remove empty line
> please.
Sure. I will do. (But unfortunately it will not happen very soon :( )
In the meantime comments and testing are appreciated. Also, I forgot
to say that, if one wants to try this, he/she will need the bootloader
to set properly the 48MHz clk for SD (for afboot use my tree -
pull-req pending on Maxime Coquelin tree). For clk driver probably my
patch for making it aware of the 48MHz setting is still needed (I've
not looked into other recent clk patches yet)..
>> +
>> + };
>> };
>>
>> &clk_hse {
>> clock-frequency = <8000000>;
>> };
>>
>> +&pinctrl {
>> + sdio-cd {
>> + sdio_cd: sdio-cd {
>> + pins {
>> + pinmux = <STM32F429_PG2_FUNC_GPIO>;
>> + bias-pull-up;
>> + };
>> + };
>> + };
>> +};
>> +
>> +&sdio {
>> + status = "okay";
>> + vmmc-supply = <&mmc_vcard>;
>> + cd-gpios = <&gpiog 2 0>;
>> + cd-inverted;
>> + pinctrl-names = "default", "opendrain", "cd";
>> + pinctrl-0 = <&sdio_pins>, <&sdio_cd>;
>> + pinctrl-1 = <&sdio_pins_od>, <&sdio_cd>;
>> + bus-width = <4>;
>> +};
>> +
>> &usart3 {
>> status = "okay";
>> };
>>
>
^ permalink raw reply
* Re: [PATCH 6/9] DT: stm32f429: add pin map for SDIO controller
From: Andrea Merello @ 2016-11-14 10:19 UTC (permalink / raw)
To: Alexandre Torgue; +Cc: Ulf Hansson, Maxime Coquelin, linux-mmc, Bruno Herrera
In-Reply-To: <3ec978cc-c80e-f350-f387-83b3e145dbe3@st.com>
On Thu, Nov 10, 2016 at 11:51 AM, Alexandre Torgue
<alexandre.torgue@st.com> wrote:
> Hi Andrea,
>
> Some minor remarks.
Hi, thank you for reviewing :)
Also adding Bruno Herrera in CC..
> On 11/08/2016 02:43 PM, Andrea Merello wrote:
>>
>> Signed-off-by: Andrea Merello <andrea.merello@gmail.com>
>> ---
>> arch/arm/boot/dts/stm32f429.dtsi | 31 +++++++++++++++++++++++++++++++
>> 1 file changed, 31 insertions(+)
>>
>> diff --git a/arch/arm/boot/dts/stm32f429.dtsi
>> b/arch/arm/boot/dts/stm32f429.dtsi
>> index 336ee4f..961bc0c 100644
>> --- a/arch/arm/boot/dts/stm32f429.dtsi
>> +++ b/arch/arm/boot/dts/stm32f429.dtsi
>> @@ -313,6 +313,37 @@
>> };
>> };
>>
>> + sdio_pins:sdio_pins@0 {
>
> Add a space after ":"
OK
>>
>> + pins {
>> + pinmux =
>> <STM32F429_PC8_FUNC_SDIO_D0>,
>> +
>> <STM32F429_PC9_FUNC_SDIO_D1>,
>> +
>> <STM32F429_PC10_FUNC_SDIO_D2>,
>> +
>> <STM32F429_PC11_FUNC_SDIO_D3>,
>> +
>> <STM32F429_PC12_FUNC_SDIO_CK>,
>> +
>> <STM32F429_PD2_FUNC_SDIO_CMD>;
>> + drive-push-pull;
>> + slew-rate = <2>;
>> + };
>> + };
>> +
>> + sdio_pins_od:sdio_pins_od@0 {
>
> same
OK
>>
>> + pins {
>> + pinmux =
>> <STM32F429_PC8_FUNC_SDIO_D0>,
>> +
>> <STM32F429_PC9_FUNC_SDIO_D1>,
>> +
>> <STM32F429_PC10_FUNC_SDIO_D2>,
>> +
>> <STM32F429_PC11_FUNC_SDIO_D3>,
>> +
>> <STM32F429_PC12_FUNC_SDIO_CK>;
>> + drive-push-pull;
>> + slew-rate = <2>;
>> + };
>> +
>> + pins_od {
>> + pinmux =
>> <STM32F429_PD2_FUNC_SDIO_CMD>;
>> + drive-open-drain;
>> + slew-rate = <2>;
>> + };
>
> Why don't use "pins1" and "pins2" instead of "pins" and "pins_od" like it is
> done for usart1?
OK
> regards
> Alex
>
>
>> + };
>> +
>
>
>
>
>
>> ethernet0_mii: mii@0 {
>> pins {
>> pinmux =
>> <STM32F429_PG13_FUNC_ETH_MII_TXD0_ETH_RMII_TXD0>,
>>
>
^ permalink raw reply
* Re: [PATCH v5 1/5] mmc: dt-bindings: add ZTE ZX296718 MMC bindings
From: Jaehoon Chung @ 2016-11-14 10:04 UTC (permalink / raw)
To: Jun Nie, Shawn Lin
Cc: Shawn Guo, xie.baoyou, Ulf Hansson, Jason Liu, linux-mmc
In-Reply-To: <CABymUCMWsCDfM58Ezpu8F7=vgpcPf_pzpbgr8OjCjOJ921tCEg@mail.gmail.com>
On 11/14/2016 07:00 PM, Jun Nie wrote:
> 2016-11-14 15:58 GMT+08:00 Shawn Lin <shawn.lin@rock-chips.com>:
>> On 2016/11/8 9:24, Jun Nie wrote:
>>>
>>> Document the device-tree binding of ZTE MMC host on
>>> ZX296718 SoC.
>>>
>>> Signed-off-by: Jun Nie <jun.nie@linaro.org>
>>> ---
>>> .../devicetree/bindings/mmc/zx-dw-mshc.txt | 35
>>> ++++++++++++++++++++++
>>> 1 file changed, 35 insertions(+)
>>> create mode 100644 Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>>>
>>> diff --git a/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>>> b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>>> new file mode 100644
>>> index 0000000..c175c4b
>>> --- /dev/null
>>> +++ b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>>> @@ -0,0 +1,35 @@
>>> +* ZTE specific extensions to the Synopsys Designware Mobile Storage
>>> + Host Controller
>>> +
>>> +The Synopsys designware mobile storage host controller is used to
>>> interface
>>> +a SoC with storage medium such as eMMC or SD/MMC cards. This file
>>> documents
>>> +differences between the core Synopsys dw mshc controller properties
>>> described
>>> +by synopsys-dw-mshc.txt and the properties used by the ZTE specific
>>> +extensions to the Synopsys Designware Mobile Storage Host Controller.
>>> +
>>> +Required Properties:
>>> +
>>> +* compatible: should be
>>> + - "zte,zx296718-dw-mshc": for ZX SoCs
>>> +
>>> +Example:
>>> +
>>> + mmc1: mmc@1110000 {
>>> + compatible = "zte,zx296718-dw-mshc";
>>> + #address-cells = <1>;
>>> + #size-cells = <0>;
>>> + reg = <0x01110000 0x1000>;
>>> + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
>>> + fifo-depth = <32>;
>>> + data-addr = <0x200>;
>>> + fifo-watermark-aligned;
>>> + bus-width = <4>;
>>> + clock-frequency = <50000000>;
>>
>>
>> do you need both clock-frequency and max-frequency here?
>
> According to dts document, clock-frequency is for clock configuration
> when dw core probe. max-frequency is for mmc core to limit max
> frequency for any cards at any time. Do you have any suggestion? Thank
> you for your time!
As i know, Jun's comment is right. :)
clock-frequency should be used with clk_set_rate().
>
>>
>>> + clocks = <&topcrm SD0_AHB>, <&topcrm SD0_WCLK>;
>>> + clock-names = "biu", "ciu";
>>> + num-slots = <1>;
>>> + max-frequency = <50000000>;
>>> + cap-sdio-irq;
>>> + cap-sd-highspeed;
>>> + status = "disabled";
>>> + };
>>>
>>
>>
>> --
>> Best Regards
>> Shawn Lin
>>
>
>
>
^ permalink raw reply
* Re: [PATCH v5 2/5] mmc: zx: Initial support for ZX mmc controller
From: Jun Nie @ 2016-11-14 10:02 UTC (permalink / raw)
To: Shawn Lin
Cc: Shawn Guo, xie.baoyou, Ulf Hansson, Jaehoon Chung, Jason Liu,
linux-mmc
In-Reply-To: <58570036-488a-9a49-bfd1-555b5d3994df@rock-chips.com>
2016-11-14 17:03 GMT+08:00 Shawn Lin <shawn.lin@rock-chips.com>:
> 在 2016/11/14 16:50, Jun Nie 写道:
>>
>> 2016-11-14 16:07 GMT+08:00 Shawn Lin <shawn.lin@rock-chips.com>:
>>>
>>> Hi, Jun,
>>>
>>> Mostly it looks fine but some minor nits.
>>>
>>>
>>> On 2016/11/8 9:24, Jun Nie wrote:
>>>>
>>>>
>>>> This platform driver adds initial support for the DW host controller
>>>> found on ZTE SoCs.
>>>>
>>>> It has been tested on ZX296718 EVB board currently. More support on
>>>> timing tuning will be added when hardware is available.
>>>>
>>>> Signed-off-by: Jun Nie <jun.nie@linaro.org>
>>>> ---
>>>> drivers/mmc/host/Kconfig | 9 ++
>>>> drivers/mmc/host/Makefile | 1 +
>>>> drivers/mmc/host/dw_mmc-zx.c | 243
>>>> +++++++++++++++++++++++++++++++++++++++++++
>>>> drivers/mmc/host/dw_mmc-zx.h | 31 ++++++
>>>> 4 files changed, 284 insertions(+)
>>>> create mode 100644 drivers/mmc/host/dw_mmc-zx.c
>>>> create mode 100644 drivers/mmc/host/dw_mmc-zx.h
>>>>
>>>> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
>>>> index 5274f50..4dafbc2 100644
>>>> --- a/drivers/mmc/host/Kconfig
>>>> +++ b/drivers/mmc/host/Kconfig
>>>> @@ -662,6 +662,15 @@ config MMC_DW_ROCKCHIP
>>>> Synopsys DesignWare Memory Card Interface driver. Select this
>>>> option
>>>> for platforms based on RK3066, RK3188 and RK3288 SoC's.
>>>>
>>>> +config MMC_DW_ZX
>>>> + tristate "ZTE specific extensions for Synopsys DW Memory Card
>>>> Interface"
>>>> + depends on MMC_DW && ARCH_ZX
>>>> + select MMC_DW_PLTFM
>>>> + help
>>>> + This selects support for ZTE SoC specific extensions to the
>>>> + Synopsys DesignWare Memory Card Interface driver. Select this
>>>> option
>>>> + for platforms based on ZX296718 SoC's.
>>>> +
>>>> config MMC_SH_MMCIF
>>>> tristate "SuperH Internal MMCIF support"
>>>> depends on HAS_DMA
>>>> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
>>>> index e2bdaaf..9766143 100644
>>>> --- a/drivers/mmc/host/Makefile
>>>> +++ b/drivers/mmc/host/Makefile
>>>> @@ -48,6 +48,7 @@ obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
>>>> obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
>>>> obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
>>>> obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o
>>>> +obj-$(CONFIG_MMC_DW_ZX) += dw_mmc-zx.o
>>>> obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
>>>> obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
>>>> obj-$(CONFIG_MMC_VUB300) += vub300.o
>>>> diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c
>>>> new file mode 100644
>>>> index 0000000..c48d851
>>>> --- /dev/null
>>>> +++ b/drivers/mmc/host/dw_mmc-zx.c
>>>> @@ -0,0 +1,243 @@
>>>> +/*
>>>> + * ZX Specific Extensions for Synopsys DW Multimedia Card Interface
>>>> driver
>>>> + *
>>>> + * Copyright (C) 2016, Linaro Ltd.
>>>> + * Copyright (C) 2016, ZTE Corp.
>>>> + *
>>>> + * 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/mfd/syscon.h>
>>>> +#include <linux/mmc/dw_mmc.h>
>>>> +#include <linux/mmc/host.h>
>>>> +#include <linux/mmc/mmc.h>
>>>> +#include <linux/module.h>
>>>> +#include <linux/of.h>
>>>> +#include <linux/platform_device.h>
>>>> +#include <linux/pm_runtime.h>
>>>> +#include <linux/regmap.h>
>>>> +#include <linux/slab.h>
>>>> +
>>>> +#include "dw_mmc.h"
>>>> +#include "dw_mmc-pltfm.h"
>>>> +#include "dw_mmc-zx.h"
>>>> +
>>>> +struct dw_mci_zx_priv_data {
>>>> + struct regmap *sysc_base;
>>>> +};
>>>> +
>>>> +enum delay_type {
>>>> + DELAY_TYPE_READ, /* read dqs delay */
>>>> + DELAY_TYPE_CLK, /* clk sample delay */
>>>> +};
>>>> +
>>>> +static int dw_mci_zx_emmc_set_delay(struct dw_mci *host, unsigned int
>>>> delay,
>>>> + enum delay_type dflag)
>>>> +{
>>>> + struct dw_mci_zx_priv_data *priv = host->priv;
>>>> + struct regmap *sysc_base = priv->sysc_base;
>>>> + unsigned int clksel;
>>>> + unsigned int loop = 1000;
>>>> + int ret;
>>>> +
>>>> + if (!sysc_base)
>>>> + return -EINVAL;
>>>> +
>>>> + ret = regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
>>>> + PARA_HALF_CLK_MODE |
>>>> PARA_DLL_BYPASS_MODE
>>>> |
>>>> + PARA_PHASE_DET_SEL_MASK |
>>>> + PARA_DLL_LOCK_NUM_MASK |
>>>> + DLL_REG_SET | PARA_DLL_START_MASK,
>>>> + PARA_DLL_START(4) |
>>>> PARA_DLL_LOCK_NUM(4));
>>>> + if (ret)
>>>> + return ret;
>>>> +
>>>> + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG1, &clksel);
>>>> + if (ret)
>>>> + return ret;
>>>> +
>>>> + if (dflag == DELAY_TYPE_CLK) {
>>>> + clksel &= ~CLK_SAMP_DELAY_MASK;
>>>> + clksel |= CLK_SAMP_DELAY(delay);
>>>> + } else {
>>>> + clksel &= ~READ_DQS_DELAY_MASK;
>>>> + clksel |= READ_DQS_DELAY(delay);
>>>> + }
>>>> +
>>>> + regmap_write(sysc_base, LB_AON_EMMC_CFG_REG1, clksel);
>>>> + regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
>>>> + PARA_DLL_START_MASK | PARA_DLL_LOCK_NUM_MASK
>>>> |
>>>> + DLL_REG_SET,
>>>> + PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4) |
>>>> + DLL_REG_SET);
>>>> +
>>>> + do {
>>>> + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG2,
>>>> &clksel);
>>>> + if (ret)
>>>> + return ret;
>>>> +
>>>> + } while (--loop && !(clksel & ZX_DLL_LOCKED));
>>>> +
>>>> + if (!loop) {
>>>> + dev_err(host->dev, "Error: %s dll lock fail\n",
>>>> __func__);
>>>> + return -EIO;
>>>> + }
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int dw_mci_zx_emmc_execute_tuning(struct dw_mci_slot *slot, u32
>>>> opcode)
>>>> +{
>>>> + struct dw_mci *host = slot->host;
>>>> + struct mmc_host *mmc = slot->mmc;
>>>> + int len, start = 0, end = 0, delay, best = 0;
>>>> +
>>>> + for (delay = 1 ; delay < 128; delay++) {
>>>> + dw_mci_zx_emmc_set_delay(host, delay, DELAY_TYPE_CLK);
>>>
>>>
>>>
>>> you never check if doing dw_mci_zx_emmc_set_delay successfully?
>>>
>> Set delay failure leads to tuning command failure. So failure case
>> will be reflected in tuning result.
>
>
> okay, I see. But doesn't that imply you could save some cpu cycle?
> Why you still try to do tuning when failing to set delay.
You are right. Skipping tuning can save CPU cycle in theory. Will
change in next version.
>
>>
>>>
>>>> + if (mmc_send_tuning(mmc, opcode, NULL)) {
>>>> + if (start >= 0) {
>>>> + end = delay - 1;
>>>> + /* check and update longest good range
>>>> */
>>>> + if ((end - start) > len) {
>>>> + best = (start + end) >> 1;
>>>> + len = end - start;
>>>> + }
>>>> + }
>>>> + start = -1;
>>>> + end = 0;
>>>> + continue;
>>>> + }
>>>> + if (start < 0)
>>>> + start = delay;
>>>> + }
>>>> +
>>>> + if (start >= 0) {
>>>> + end = delay - 1;
>>>> + if ((end - start) > len) {
>>>> + best = (start + end) >> 1;
>>>> + len = end - start;
>>>> + }
>>>> + }
>>>> + if (best < 0)
>>>> + return -EIO;
>>>> +
>>>> + dev_info(host->dev, "%s best range: start %d end %d\n",
>>>> __func__,
>>>> + start, end);
>>>> + dw_mci_zx_emmc_set_delay(host, best, DELAY_TYPE_CLK);
>>>
>>>
>>>
>>> ditto.
>>>
>>>
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int dw_mci_zx_prepare_hs400_tuning(struct dw_mci *host,
>>>> + struct mmc_ios *ios)
>>>> +{
>>>> + int ret;
>>>> +
>>>> + /* config phase shift as 90 degree */
>>>> + ret = dw_mci_zx_emmc_set_delay(host, 32, DELAY_TYPE_READ);
>>>> + if (ret < 0)
>>>> + return -EIO;
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int dw_mci_zx_execute_tuning(struct dw_mci_slot *slot, u32
>>>> opcode)
>>>> +{
>>>> + struct dw_mci *host = slot->host;
>>>> +
>>>> + if (host->verid == 0x290a) /* only for emmc */
>>>> + return dw_mci_zx_emmc_execute_tuning(slot, opcode);
>>>> + /* TODO: Add 0x210a dedicated tuning for sd/sdio */
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static int dw_mci_zx_parse_dt(struct dw_mci *host)
>>>> +{
>>>> + struct device_node *np = host->dev->of_node;
>>>> + struct device_node *node;
>>>> + struct dw_mci_zx_priv_data *priv;
>>>> + struct regmap *sysc_base;
>>>> + int ret;
>>>> +
>>>> + /* syscon is needed only by emmc */
>>>> + node = of_parse_phandle(np, "zte,aon-syscon", 0);
>>>> + if (node) {
>>>> + sysc_base = syscon_node_to_regmap(node);
>>>> + of_node_put(node);
>>>> +
>>>> + if (IS_ERR(sysc_base)) {
>>>> + ret = PTR_ERR(sysc_base);
>>>> + if (ret != -EPROBE_DEFER)
>>>> + dev_err(host->dev, "Can't get syscon:
>>>> %d\n",
>>>> + ret);
>>>> + return ret;
>>>> + }
>>>> + } else {
>>>> + return 0;
>>>> + }
>>>> +
>>>> + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
>>>> + if (!priv)
>>>> + return -ENOMEM;
>>>> + priv->sysc_base = sysc_base;
>>>> + host->priv = priv;
>>>> +
>>>> + return 0;
>>>> +}
>>>> +
>>>> +static unsigned long zx_dwmmc_caps[3] = {
>>>> + MMC_CAP_CMD23,
>>>> + MMC_CAP_CMD23,
>>>> + MMC_CAP_CMD23,
>>>> +};
>>>> +
>>>> +static const struct dw_mci_drv_data zx_drv_data = {
>>>> + .caps = zx_dwmmc_caps,
>>>> + .execute_tuning = dw_mci_zx_execute_tuning,
>>>> + .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning,
>>>> + .parse_dt = dw_mci_zx_parse_dt,
>>>> +};
>>>> +
>>>> +static const struct of_device_id dw_mci_zx_match[] = {
>>>> + { .compatible = "zte,zx296718-dw-mshc", .data = &zx_drv_data},
>>>> + {},
>>>> +};
>>>> +MODULE_DEVICE_TABLE(of, dw_mci_zx_match);
>>>> +
>>>> +static int dw_mci_zx_probe(struct platform_device *pdev)
>>>> +{
>>>> + const struct dw_mci_drv_data *drv_data;
>>>> + const struct of_device_id *match;
>>>> +
>>>> + match = of_match_node(dw_mci_zx_match, pdev->dev.of_node);
>>>> + drv_data = match->data;
>>>> +
>>>> + return dw_mci_pltfm_register(pdev, drv_data);
>>>> +}
>>>> +
>>>> +static const struct dev_pm_ops dw_mci_zx_dev_pm_ops = {
>>>> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
>>>> + pm_runtime_force_resume)
>>>> + SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
>>>> + dw_mci_runtime_resume,
>>>> + NULL)
>>>> +};
>>>> +
>>>> +static struct platform_driver dw_mci_zx_pltfm_driver = {
>>>> + .probe = dw_mci_zx_probe,
>>>> + .remove = dw_mci_pltfm_remove,
>>>> + .driver = {
>>>> + .name = "dwmmc_zx",
>>>> + .of_match_table = dw_mci_zx_match,
>>>> + .pm = &dw_mci_zx_dev_pm_ops,
>>>> + },
>>>> +};
>>>> +
>>>> +module_platform_driver(dw_mci_zx_pltfm_driver);
>>>> +
>>>> +MODULE_DESCRIPTION("ZTE emmc/sd driver");
>>>> +MODULE_LICENSE("GPL v2");
>>>> diff --git a/drivers/mmc/host/dw_mmc-zx.h b/drivers/mmc/host/dw_mmc-zx.h
>>>> new file mode 100644
>>>> index 0000000..f369997
>>>> --- /dev/null
>>>> +++ b/drivers/mmc/host/dw_mmc-zx.h
>>>> @@ -0,0 +1,31 @@
>>>> +#ifndef _DW_MMC_ZX_H_
>>>> +#define _DW_MMC_ZX_H_
>>>> +
>>>> +/* ZX296718 SoC specific DLL register offset. */
>>>> +#define LB_AON_EMMC_CFG_REG0 0x1B0
>>>> +#define LB_AON_EMMC_CFG_REG1 0x1B4
>>>> +#define LB_AON_EMMC_CFG_REG2 0x1B8
>>>> +
>>>> +/* LB_AON_EMMC_CFG_REG0 register defines */
>>>> +#define PARA_DLL_START(x) ((x) & 0xFF)
>>>> +#define PARA_DLL_START_MASK 0xFF
>>>> +#define DLL_REG_SET BIT(8)
>>>> +#define PARA_DLL_LOCK_NUM(x) (((x) & 7) << 16)
>>>> +#define PARA_DLL_LOCK_NUM_MASK (7 << 16)
>>>> +#define PARA_PHASE_DET_SEL(x) (((x) & 7) << 20)
>>>> +#define PARA_PHASE_DET_SEL_MASK (7 << 20)
>>>> +#define PARA_DLL_BYPASS_MODE BIT(23)
>>>> +#define PARA_HALF_CLK_MODE BIT(24)
>>>> +
>>>> +/* LB_AON_EMMC_CFG_REG1 register defines */
>>>> +#define READ_DQS_DELAY(x) ((x) & 0x7F)
>>>> +#define READ_DQS_DELAY_MASK (0x7F)
>>>> +#define READ_DQS_BYPASS_MODE BIT(7)
>>>> +#define CLK_SAMP_DELAY(x) (((x) & 0x7F) << 8)
>>>> +#define CLK_SAMP_DELAY_MASK (0x7F << 8)
>>>> +#define CLK_SAMP_BYPASS_MODE BIT(15)
>>>> +
>>>> +/* LB_AON_EMMC_CFG_REG2 register defines */
>>>> +#define ZX_DLL_LOCKED BIT(2)
>>>> +
>>>> +#endif /* _DW_MMC_ZX_H_ */
>>>>
>>>
>>>
>>> --
>>> Best Regards
>>> Shawn Lin
>>>
>> --
>> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
>> the body of a message to majordomo@vger.kernel.org
>> More majordomo info at http://vger.kernel.org/majordomo-info.html
>>
>
>
> --
> Best Regards
> Shawn Lin
>
^ permalink raw reply
* Re: [PATCH v5 1/5] mmc: dt-bindings: add ZTE ZX296718 MMC bindings
From: Jun Nie @ 2016-11-14 10:00 UTC (permalink / raw)
To: Shawn Lin
Cc: Shawn Guo, xie.baoyou, Ulf Hansson, Jaehoon Chung, Jason Liu,
linux-mmc
In-Reply-To: <b72dcd9c-aa90-a487-dbfb-6682fcdf015b@rock-chips.com>
2016-11-14 15:58 GMT+08:00 Shawn Lin <shawn.lin@rock-chips.com>:
> On 2016/11/8 9:24, Jun Nie wrote:
>>
>> Document the device-tree binding of ZTE MMC host on
>> ZX296718 SoC.
>>
>> Signed-off-by: Jun Nie <jun.nie@linaro.org>
>> ---
>> .../devicetree/bindings/mmc/zx-dw-mshc.txt | 35
>> ++++++++++++++++++++++
>> 1 file changed, 35 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>>
>> diff --git a/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>> b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>> new file mode 100644
>> index 0000000..c175c4b
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>> @@ -0,0 +1,35 @@
>> +* ZTE specific extensions to the Synopsys Designware Mobile Storage
>> + Host Controller
>> +
>> +The Synopsys designware mobile storage host controller is used to
>> interface
>> +a SoC with storage medium such as eMMC or SD/MMC cards. This file
>> documents
>> +differences between the core Synopsys dw mshc controller properties
>> described
>> +by synopsys-dw-mshc.txt and the properties used by the ZTE specific
>> +extensions to the Synopsys Designware Mobile Storage Host Controller.
>> +
>> +Required Properties:
>> +
>> +* compatible: should be
>> + - "zte,zx296718-dw-mshc": for ZX SoCs
>> +
>> +Example:
>> +
>> + mmc1: mmc@1110000 {
>> + compatible = "zte,zx296718-dw-mshc";
>> + #address-cells = <1>;
>> + #size-cells = <0>;
>> + reg = <0x01110000 0x1000>;
>> + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
>> + fifo-depth = <32>;
>> + data-addr = <0x200>;
>> + fifo-watermark-aligned;
>> + bus-width = <4>;
>> + clock-frequency = <50000000>;
>
>
> do you need both clock-frequency and max-frequency here?
According to dts document, clock-frequency is for clock configuration
when dw core probe. max-frequency is for mmc core to limit max
frequency for any cards at any time. Do you have any suggestion? Thank
you for your time!
>
>> + clocks = <&topcrm SD0_AHB>, <&topcrm SD0_WCLK>;
>> + clock-names = "biu", "ciu";
>> + num-slots = <1>;
>> + max-frequency = <50000000>;
>> + cap-sdio-irq;
>> + cap-sd-highspeed;
>> + status = "disabled";
>> + };
>>
>
>
> --
> Best Regards
> Shawn Lin
>
^ permalink raw reply
* Re: [PATCH v2] mmc: sdhci-of-esdhc: fixup PRESENT_STATE read
From: Michael Walle @ 2016-11-14 9:52 UTC (permalink / raw)
To: Adrian Hunter; +Cc: Y.B. Lu, linux-kernel, linux-mmc, Ulf Hansson, yangbo lu
In-Reply-To: <3682f94a-187a-b4f3-0b77-8804ee16c9ba@intel.com>
Am 2016-11-14 10:37, schrieb Adrian Hunter:
> On 14/11/16 10:50, Michael Walle wrote:
>> Am 2016-11-14 04:00, schrieb Y.B. Lu:
>>>> -----Original Message-----
>>>> From: Michael Walle [mailto:michael@walle.cc]
>>>> Sent: Saturday, November 12, 2016 12:04 AM
>>>> To: linux-kernel@vger.kernel.org
>>>> Cc: linux-mmc@vger.kernel.org; Ulf Hansson; Adrian Hunter; yangbo
>>>> lu;
>>>> Michael Walle
>>>> Subject: [PATCH v2] mmc: sdhci-of-esdhc: fixup PRESENT_STATE read
>>>>
>>>> Since commit 87a18a6a5652 ("mmc: mmc: Use ->card_busy() to detect
>>>> busy
>>>> cards in __mmc_switch()") the ESDHC driver is broken:
>>>> mmc0: Card stuck in programming state! __mmc_switch
>>>> mmc0: error -110 whilst initialising MMC card
>>>>
>>>> Since this commit __mmc_switch() uses ->card_busy(), which is
>>>> sdhci_card_busy() for the esdhc driver. sdhci_card_busy() uses the
>>>> PRESENT_STATE register, specifically the DAT0 signal level bit. But
>>>> the
>>>> ESDHC uses a non-conformant PRESENT_STATE register, thus a read
>>>> fixup is
>>>> required to make the driver work again.
>>>>
>>>> Signed-off-by: Michael Walle <michael@walle.cc>
>>>> Fixes: 87a18a6a5652 ("mmc: mmc: Use ->card_busy() to detect busy
>>>> cards in
>>>> __mmc_switch()")
>>>> ---
>>>> v2:
>>>> - use lower bits of the original value (that was actually a typo)
>>>> - add fixes tag
>>>> - fix typo
>>>>
>>>> drivers/mmc/host/sdhci-of-esdhc.c | 12 ++++++++++++
>>>> 1 file changed, 12 insertions(+)
>>>>
>>>> diff --git a/drivers/mmc/host/sdhci-of-esdhc.c
>>>> b/drivers/mmc/host/sdhci-
>>>> of-esdhc.c
>>>> index fb71c86..f9c84bb 100644
>>>> --- a/drivers/mmc/host/sdhci-of-esdhc.c
>>>> +++ b/drivers/mmc/host/sdhci-of-esdhc.c
>>>> @@ -66,6 +66,18 @@ static u32 esdhc_readl_fixup(struct sdhci_host
>>>> *host,
>>>> return ret;
>>>> }
>>>> }
>>>> + /*
>>>> + * The DAT[3:0] line signal levels and the CMD line signal
>>>> level is
>>>> + * not compatible with standard SDHC register. Move the
>>>> corresponding
>>>> + * bits around.
>>>> + */
>>>> + if (spec_reg == SDHCI_PRESENT_STATE) {
>>>> + ret = value & ~0xf8000000;
>>>
>>> [Lu Yangbo-B47093] I think the bits which should be cleaned before
>>> following '|=' are 0x01f00000 not 0xf8000000, right?
>>> :)
>>
>> Its neither 0x01f00000 nor 0xf8000000 :( I'll put the bits definition
>> into
>> the comment the next time, so everyone can review them. bit[31:24] are
>> the
>> line DAT[7:0] line signal level. bit[23] is command signal level. All
>> other
>> bits are the same as in the standard SDHC PRESENT_STATE register.
>>
>> I want to keep all but the upper 9 bits from the original value,
>> therefore,
>> this should be the correct mask:
>> ret = value & ~0xff800000;
>
> Why keep bits 22:20 ? Isn't it more logical to keep 19:0 (i.e. ret =
> value
> & 0xfffff)
These are 0 according to the datasheet but of course, it makes more
sense to mask these, too.
-michael
^ permalink raw reply
* Re: [PATCH v2] mmc: sdhci-of-esdhc: fixup PRESENT_STATE read
From: Adrian Hunter @ 2016-11-14 9:37 UTC (permalink / raw)
To: Michael Walle, Y.B. Lu; +Cc: linux-kernel, linux-mmc, Ulf Hansson, yangbo lu
In-Reply-To: <1c1e557a605312a4bf2a1feb44d940e9@walle.cc>
On 14/11/16 10:50, Michael Walle wrote:
> Am 2016-11-14 04:00, schrieb Y.B. Lu:
>>> -----Original Message-----
>>> From: Michael Walle [mailto:michael@walle.cc]
>>> Sent: Saturday, November 12, 2016 12:04 AM
>>> To: linux-kernel@vger.kernel.org
>>> Cc: linux-mmc@vger.kernel.org; Ulf Hansson; Adrian Hunter; yangbo lu;
>>> Michael Walle
>>> Subject: [PATCH v2] mmc: sdhci-of-esdhc: fixup PRESENT_STATE read
>>>
>>> Since commit 87a18a6a5652 ("mmc: mmc: Use ->card_busy() to detect busy
>>> cards in __mmc_switch()") the ESDHC driver is broken:
>>> mmc0: Card stuck in programming state! __mmc_switch
>>> mmc0: error -110 whilst initialising MMC card
>>>
>>> Since this commit __mmc_switch() uses ->card_busy(), which is
>>> sdhci_card_busy() for the esdhc driver. sdhci_card_busy() uses the
>>> PRESENT_STATE register, specifically the DAT0 signal level bit. But the
>>> ESDHC uses a non-conformant PRESENT_STATE register, thus a read fixup is
>>> required to make the driver work again.
>>>
>>> Signed-off-by: Michael Walle <michael@walle.cc>
>>> Fixes: 87a18a6a5652 ("mmc: mmc: Use ->card_busy() to detect busy cards in
>>> __mmc_switch()")
>>> ---
>>> v2:
>>> - use lower bits of the original value (that was actually a typo)
>>> - add fixes tag
>>> - fix typo
>>>
>>> drivers/mmc/host/sdhci-of-esdhc.c | 12 ++++++++++++
>>> 1 file changed, 12 insertions(+)
>>>
>>> diff --git a/drivers/mmc/host/sdhci-of-esdhc.c b/drivers/mmc/host/sdhci-
>>> of-esdhc.c
>>> index fb71c86..f9c84bb 100644
>>> --- a/drivers/mmc/host/sdhci-of-esdhc.c
>>> +++ b/drivers/mmc/host/sdhci-of-esdhc.c
>>> @@ -66,6 +66,18 @@ static u32 esdhc_readl_fixup(struct sdhci_host *host,
>>> return ret;
>>> }
>>> }
>>> + /*
>>> + * The DAT[3:0] line signal levels and the CMD line signal level is
>>> + * not compatible with standard SDHC register. Move the
>>> corresponding
>>> + * bits around.
>>> + */
>>> + if (spec_reg == SDHCI_PRESENT_STATE) {
>>> + ret = value & ~0xf8000000;
>>
>> [Lu Yangbo-B47093] I think the bits which should be cleaned before
>> following '|=' are 0x01f00000 not 0xf8000000, right?
>> :)
>
> Its neither 0x01f00000 nor 0xf8000000 :( I'll put the bits definition into
> the comment the next time, so everyone can review them. bit[31:24] are the
> line DAT[7:0] line signal level. bit[23] is command signal level. All other
> bits are the same as in the standard SDHC PRESENT_STATE register.
>
> I want to keep all but the upper 9 bits from the original value, therefore,
> this should be the correct mask:
> ret = value & ~0xff800000;
Why keep bits 22:20 ? Isn't it more logical to keep 19:0 (i.e. ret = value
& 0xfffff)
>
> -michael
>
>>
>>> + ret |= (value >> 4) & SDHCI_DATA_LVL_MASK;
>>> + ret |= (value << 1) & 0x01000000;
>>> + return ret;
>>> + }
>>> +
>>> ret = value;
>>> return ret;
>>> }
>>> --
>>> 2.1.4
>
>
^ permalink raw reply
* Re: [PATCH v5 2/5] mmc: zx: Initial support for ZX mmc controller
From: Shawn Lin @ 2016-11-14 9:03 UTC (permalink / raw)
To: Jun Nie
Cc: shawn.lin, Shawn Guo, xie.baoyou, Ulf Hansson, Jaehoon Chung,
Jason Liu, linux-mmc
In-Reply-To: <CABymUCOSDioY9pPwyAVJRr+F4FU9-+TxG4zbQajPvQ0QTxT3Ag@mail.gmail.com>
在 2016/11/14 16:50, Jun Nie 写道:
> 2016-11-14 16:07 GMT+08:00 Shawn Lin <shawn.lin@rock-chips.com>:
>> Hi, Jun,
>>
>> Mostly it looks fine but some minor nits.
>>
>>
>> On 2016/11/8 9:24, Jun Nie wrote:
>>>
>>> This platform driver adds initial support for the DW host controller
>>> found on ZTE SoCs.
>>>
>>> It has been tested on ZX296718 EVB board currently. More support on
>>> timing tuning will be added when hardware is available.
>>>
>>> Signed-off-by: Jun Nie <jun.nie@linaro.org>
>>> ---
>>> drivers/mmc/host/Kconfig | 9 ++
>>> drivers/mmc/host/Makefile | 1 +
>>> drivers/mmc/host/dw_mmc-zx.c | 243
>>> +++++++++++++++++++++++++++++++++++++++++++
>>> drivers/mmc/host/dw_mmc-zx.h | 31 ++++++
>>> 4 files changed, 284 insertions(+)
>>> create mode 100644 drivers/mmc/host/dw_mmc-zx.c
>>> create mode 100644 drivers/mmc/host/dw_mmc-zx.h
>>>
>>> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
>>> index 5274f50..4dafbc2 100644
>>> --- a/drivers/mmc/host/Kconfig
>>> +++ b/drivers/mmc/host/Kconfig
>>> @@ -662,6 +662,15 @@ config MMC_DW_ROCKCHIP
>>> Synopsys DesignWare Memory Card Interface driver. Select this
>>> option
>>> for platforms based on RK3066, RK3188 and RK3288 SoC's.
>>>
>>> +config MMC_DW_ZX
>>> + tristate "ZTE specific extensions for Synopsys DW Memory Card
>>> Interface"
>>> + depends on MMC_DW && ARCH_ZX
>>> + select MMC_DW_PLTFM
>>> + help
>>> + This selects support for ZTE SoC specific extensions to the
>>> + Synopsys DesignWare Memory Card Interface driver. Select this
>>> option
>>> + for platforms based on ZX296718 SoC's.
>>> +
>>> config MMC_SH_MMCIF
>>> tristate "SuperH Internal MMCIF support"
>>> depends on HAS_DMA
>>> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
>>> index e2bdaaf..9766143 100644
>>> --- a/drivers/mmc/host/Makefile
>>> +++ b/drivers/mmc/host/Makefile
>>> @@ -48,6 +48,7 @@ obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
>>> obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
>>> obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
>>> obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o
>>> +obj-$(CONFIG_MMC_DW_ZX) += dw_mmc-zx.o
>>> obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
>>> obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
>>> obj-$(CONFIG_MMC_VUB300) += vub300.o
>>> diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c
>>> new file mode 100644
>>> index 0000000..c48d851
>>> --- /dev/null
>>> +++ b/drivers/mmc/host/dw_mmc-zx.c
>>> @@ -0,0 +1,243 @@
>>> +/*
>>> + * ZX Specific Extensions for Synopsys DW Multimedia Card Interface
>>> driver
>>> + *
>>> + * Copyright (C) 2016, Linaro Ltd.
>>> + * Copyright (C) 2016, ZTE Corp.
>>> + *
>>> + * 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/mfd/syscon.h>
>>> +#include <linux/mmc/dw_mmc.h>
>>> +#include <linux/mmc/host.h>
>>> +#include <linux/mmc/mmc.h>
>>> +#include <linux/module.h>
>>> +#include <linux/of.h>
>>> +#include <linux/platform_device.h>
>>> +#include <linux/pm_runtime.h>
>>> +#include <linux/regmap.h>
>>> +#include <linux/slab.h>
>>> +
>>> +#include "dw_mmc.h"
>>> +#include "dw_mmc-pltfm.h"
>>> +#include "dw_mmc-zx.h"
>>> +
>>> +struct dw_mci_zx_priv_data {
>>> + struct regmap *sysc_base;
>>> +};
>>> +
>>> +enum delay_type {
>>> + DELAY_TYPE_READ, /* read dqs delay */
>>> + DELAY_TYPE_CLK, /* clk sample delay */
>>> +};
>>> +
>>> +static int dw_mci_zx_emmc_set_delay(struct dw_mci *host, unsigned int
>>> delay,
>>> + enum delay_type dflag)
>>> +{
>>> + struct dw_mci_zx_priv_data *priv = host->priv;
>>> + struct regmap *sysc_base = priv->sysc_base;
>>> + unsigned int clksel;
>>> + unsigned int loop = 1000;
>>> + int ret;
>>> +
>>> + if (!sysc_base)
>>> + return -EINVAL;
>>> +
>>> + ret = regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
>>> + PARA_HALF_CLK_MODE | PARA_DLL_BYPASS_MODE
>>> |
>>> + PARA_PHASE_DET_SEL_MASK |
>>> + PARA_DLL_LOCK_NUM_MASK |
>>> + DLL_REG_SET | PARA_DLL_START_MASK,
>>> + PARA_DLL_START(4) |
>>> PARA_DLL_LOCK_NUM(4));
>>> + if (ret)
>>> + return ret;
>>> +
>>> + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG1, &clksel);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + if (dflag == DELAY_TYPE_CLK) {
>>> + clksel &= ~CLK_SAMP_DELAY_MASK;
>>> + clksel |= CLK_SAMP_DELAY(delay);
>>> + } else {
>>> + clksel &= ~READ_DQS_DELAY_MASK;
>>> + clksel |= READ_DQS_DELAY(delay);
>>> + }
>>> +
>>> + regmap_write(sysc_base, LB_AON_EMMC_CFG_REG1, clksel);
>>> + regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
>>> + PARA_DLL_START_MASK | PARA_DLL_LOCK_NUM_MASK |
>>> + DLL_REG_SET,
>>> + PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4) |
>>> + DLL_REG_SET);
>>> +
>>> + do {
>>> + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG2,
>>> &clksel);
>>> + if (ret)
>>> + return ret;
>>> +
>>> + } while (--loop && !(clksel & ZX_DLL_LOCKED));
>>> +
>>> + if (!loop) {
>>> + dev_err(host->dev, "Error: %s dll lock fail\n", __func__);
>>> + return -EIO;
>>> + }
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int dw_mci_zx_emmc_execute_tuning(struct dw_mci_slot *slot, u32
>>> opcode)
>>> +{
>>> + struct dw_mci *host = slot->host;
>>> + struct mmc_host *mmc = slot->mmc;
>>> + int len, start = 0, end = 0, delay, best = 0;
>>> +
>>> + for (delay = 1 ; delay < 128; delay++) {
>>> + dw_mci_zx_emmc_set_delay(host, delay, DELAY_TYPE_CLK);
>>
>>
>> you never check if doing dw_mci_zx_emmc_set_delay successfully?
>>
> Set delay failure leads to tuning command failure. So failure case
> will be reflected in tuning result.
okay, I see. But doesn't that imply you could save some cpu cycle?
Why you still try to do tuning when failing to set delay.
>
>>
>>> + if (mmc_send_tuning(mmc, opcode, NULL)) {
>>> + if (start >= 0) {
>>> + end = delay - 1;
>>> + /* check and update longest good range */
>>> + if ((end - start) > len) {
>>> + best = (start + end) >> 1;
>>> + len = end - start;
>>> + }
>>> + }
>>> + start = -1;
>>> + end = 0;
>>> + continue;
>>> + }
>>> + if (start < 0)
>>> + start = delay;
>>> + }
>>> +
>>> + if (start >= 0) {
>>> + end = delay - 1;
>>> + if ((end - start) > len) {
>>> + best = (start + end) >> 1;
>>> + len = end - start;
>>> + }
>>> + }
>>> + if (best < 0)
>>> + return -EIO;
>>> +
>>> + dev_info(host->dev, "%s best range: start %d end %d\n", __func__,
>>> + start, end);
>>> + dw_mci_zx_emmc_set_delay(host, best, DELAY_TYPE_CLK);
>>
>>
>> ditto.
>>
>>
>>> + return 0;
>>> +}
>>> +
>>> +static int dw_mci_zx_prepare_hs400_tuning(struct dw_mci *host,
>>> + struct mmc_ios *ios)
>>> +{
>>> + int ret;
>>> +
>>> + /* config phase shift as 90 degree */
>>> + ret = dw_mci_zx_emmc_set_delay(host, 32, DELAY_TYPE_READ);
>>> + if (ret < 0)
>>> + return -EIO;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int dw_mci_zx_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
>>> +{
>>> + struct dw_mci *host = slot->host;
>>> +
>>> + if (host->verid == 0x290a) /* only for emmc */
>>> + return dw_mci_zx_emmc_execute_tuning(slot, opcode);
>>> + /* TODO: Add 0x210a dedicated tuning for sd/sdio */
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static int dw_mci_zx_parse_dt(struct dw_mci *host)
>>> +{
>>> + struct device_node *np = host->dev->of_node;
>>> + struct device_node *node;
>>> + struct dw_mci_zx_priv_data *priv;
>>> + struct regmap *sysc_base;
>>> + int ret;
>>> +
>>> + /* syscon is needed only by emmc */
>>> + node = of_parse_phandle(np, "zte,aon-syscon", 0);
>>> + if (node) {
>>> + sysc_base = syscon_node_to_regmap(node);
>>> + of_node_put(node);
>>> +
>>> + if (IS_ERR(sysc_base)) {
>>> + ret = PTR_ERR(sysc_base);
>>> + if (ret != -EPROBE_DEFER)
>>> + dev_err(host->dev, "Can't get syscon:
>>> %d\n",
>>> + ret);
>>> + return ret;
>>> + }
>>> + } else {
>>> + return 0;
>>> + }
>>> +
>>> + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
>>> + if (!priv)
>>> + return -ENOMEM;
>>> + priv->sysc_base = sysc_base;
>>> + host->priv = priv;
>>> +
>>> + return 0;
>>> +}
>>> +
>>> +static unsigned long zx_dwmmc_caps[3] = {
>>> + MMC_CAP_CMD23,
>>> + MMC_CAP_CMD23,
>>> + MMC_CAP_CMD23,
>>> +};
>>> +
>>> +static const struct dw_mci_drv_data zx_drv_data = {
>>> + .caps = zx_dwmmc_caps,
>>> + .execute_tuning = dw_mci_zx_execute_tuning,
>>> + .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning,
>>> + .parse_dt = dw_mci_zx_parse_dt,
>>> +};
>>> +
>>> +static const struct of_device_id dw_mci_zx_match[] = {
>>> + { .compatible = "zte,zx296718-dw-mshc", .data = &zx_drv_data},
>>> + {},
>>> +};
>>> +MODULE_DEVICE_TABLE(of, dw_mci_zx_match);
>>> +
>>> +static int dw_mci_zx_probe(struct platform_device *pdev)
>>> +{
>>> + const struct dw_mci_drv_data *drv_data;
>>> + const struct of_device_id *match;
>>> +
>>> + match = of_match_node(dw_mci_zx_match, pdev->dev.of_node);
>>> + drv_data = match->data;
>>> +
>>> + return dw_mci_pltfm_register(pdev, drv_data);
>>> +}
>>> +
>>> +static const struct dev_pm_ops dw_mci_zx_dev_pm_ops = {
>>> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
>>> + pm_runtime_force_resume)
>>> + SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
>>> + dw_mci_runtime_resume,
>>> + NULL)
>>> +};
>>> +
>>> +static struct platform_driver dw_mci_zx_pltfm_driver = {
>>> + .probe = dw_mci_zx_probe,
>>> + .remove = dw_mci_pltfm_remove,
>>> + .driver = {
>>> + .name = "dwmmc_zx",
>>> + .of_match_table = dw_mci_zx_match,
>>> + .pm = &dw_mci_zx_dev_pm_ops,
>>> + },
>>> +};
>>> +
>>> +module_platform_driver(dw_mci_zx_pltfm_driver);
>>> +
>>> +MODULE_DESCRIPTION("ZTE emmc/sd driver");
>>> +MODULE_LICENSE("GPL v2");
>>> diff --git a/drivers/mmc/host/dw_mmc-zx.h b/drivers/mmc/host/dw_mmc-zx.h
>>> new file mode 100644
>>> index 0000000..f369997
>>> --- /dev/null
>>> +++ b/drivers/mmc/host/dw_mmc-zx.h
>>> @@ -0,0 +1,31 @@
>>> +#ifndef _DW_MMC_ZX_H_
>>> +#define _DW_MMC_ZX_H_
>>> +
>>> +/* ZX296718 SoC specific DLL register offset. */
>>> +#define LB_AON_EMMC_CFG_REG0 0x1B0
>>> +#define LB_AON_EMMC_CFG_REG1 0x1B4
>>> +#define LB_AON_EMMC_CFG_REG2 0x1B8
>>> +
>>> +/* LB_AON_EMMC_CFG_REG0 register defines */
>>> +#define PARA_DLL_START(x) ((x) & 0xFF)
>>> +#define PARA_DLL_START_MASK 0xFF
>>> +#define DLL_REG_SET BIT(8)
>>> +#define PARA_DLL_LOCK_NUM(x) (((x) & 7) << 16)
>>> +#define PARA_DLL_LOCK_NUM_MASK (7 << 16)
>>> +#define PARA_PHASE_DET_SEL(x) (((x) & 7) << 20)
>>> +#define PARA_PHASE_DET_SEL_MASK (7 << 20)
>>> +#define PARA_DLL_BYPASS_MODE BIT(23)
>>> +#define PARA_HALF_CLK_MODE BIT(24)
>>> +
>>> +/* LB_AON_EMMC_CFG_REG1 register defines */
>>> +#define READ_DQS_DELAY(x) ((x) & 0x7F)
>>> +#define READ_DQS_DELAY_MASK (0x7F)
>>> +#define READ_DQS_BYPASS_MODE BIT(7)
>>> +#define CLK_SAMP_DELAY(x) (((x) & 0x7F) << 8)
>>> +#define CLK_SAMP_DELAY_MASK (0x7F << 8)
>>> +#define CLK_SAMP_BYPASS_MODE BIT(15)
>>> +
>>> +/* LB_AON_EMMC_CFG_REG2 register defines */
>>> +#define ZX_DLL_LOCKED BIT(2)
>>> +
>>> +#endif /* _DW_MMC_ZX_H_ */
>>>
>>
>>
>> --
>> Best Regards
>> Shawn Lin
>>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-mmc" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Best Regards
Shawn Lin
^ permalink raw reply
* Re: [PATCH v5 2/5] mmc: zx: Initial support for ZX mmc controller
From: Jun Nie @ 2016-11-14 8:50 UTC (permalink / raw)
To: Shawn Lin
Cc: Shawn Guo, xie.baoyou, Ulf Hansson, Jaehoon Chung, Jason Liu,
linux-mmc
In-Reply-To: <8fbabe63-a4df-a368-9f6e-ddaf996b4023@rock-chips.com>
2016-11-14 16:07 GMT+08:00 Shawn Lin <shawn.lin@rock-chips.com>:
> Hi, Jun,
>
> Mostly it looks fine but some minor nits.
>
>
> On 2016/11/8 9:24, Jun Nie wrote:
>>
>> This platform driver adds initial support for the DW host controller
>> found on ZTE SoCs.
>>
>> It has been tested on ZX296718 EVB board currently. More support on
>> timing tuning will be added when hardware is available.
>>
>> Signed-off-by: Jun Nie <jun.nie@linaro.org>
>> ---
>> drivers/mmc/host/Kconfig | 9 ++
>> drivers/mmc/host/Makefile | 1 +
>> drivers/mmc/host/dw_mmc-zx.c | 243
>> +++++++++++++++++++++++++++++++++++++++++++
>> drivers/mmc/host/dw_mmc-zx.h | 31 ++++++
>> 4 files changed, 284 insertions(+)
>> create mode 100644 drivers/mmc/host/dw_mmc-zx.c
>> create mode 100644 drivers/mmc/host/dw_mmc-zx.h
>>
>> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
>> index 5274f50..4dafbc2 100644
>> --- a/drivers/mmc/host/Kconfig
>> +++ b/drivers/mmc/host/Kconfig
>> @@ -662,6 +662,15 @@ config MMC_DW_ROCKCHIP
>> Synopsys DesignWare Memory Card Interface driver. Select this
>> option
>> for platforms based on RK3066, RK3188 and RK3288 SoC's.
>>
>> +config MMC_DW_ZX
>> + tristate "ZTE specific extensions for Synopsys DW Memory Card
>> Interface"
>> + depends on MMC_DW && ARCH_ZX
>> + select MMC_DW_PLTFM
>> + help
>> + This selects support for ZTE SoC specific extensions to the
>> + Synopsys DesignWare Memory Card Interface driver. Select this
>> option
>> + for platforms based on ZX296718 SoC's.
>> +
>> config MMC_SH_MMCIF
>> tristate "SuperH Internal MMCIF support"
>> depends on HAS_DMA
>> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
>> index e2bdaaf..9766143 100644
>> --- a/drivers/mmc/host/Makefile
>> +++ b/drivers/mmc/host/Makefile
>> @@ -48,6 +48,7 @@ obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
>> obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
>> obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
>> obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o
>> +obj-$(CONFIG_MMC_DW_ZX) += dw_mmc-zx.o
>> obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
>> obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
>> obj-$(CONFIG_MMC_VUB300) += vub300.o
>> diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c
>> new file mode 100644
>> index 0000000..c48d851
>> --- /dev/null
>> +++ b/drivers/mmc/host/dw_mmc-zx.c
>> @@ -0,0 +1,243 @@
>> +/*
>> + * ZX Specific Extensions for Synopsys DW Multimedia Card Interface
>> driver
>> + *
>> + * Copyright (C) 2016, Linaro Ltd.
>> + * Copyright (C) 2016, ZTE Corp.
>> + *
>> + * 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/mfd/syscon.h>
>> +#include <linux/mmc/dw_mmc.h>
>> +#include <linux/mmc/host.h>
>> +#include <linux/mmc/mmc.h>
>> +#include <linux/module.h>
>> +#include <linux/of.h>
>> +#include <linux/platform_device.h>
>> +#include <linux/pm_runtime.h>
>> +#include <linux/regmap.h>
>> +#include <linux/slab.h>
>> +
>> +#include "dw_mmc.h"
>> +#include "dw_mmc-pltfm.h"
>> +#include "dw_mmc-zx.h"
>> +
>> +struct dw_mci_zx_priv_data {
>> + struct regmap *sysc_base;
>> +};
>> +
>> +enum delay_type {
>> + DELAY_TYPE_READ, /* read dqs delay */
>> + DELAY_TYPE_CLK, /* clk sample delay */
>> +};
>> +
>> +static int dw_mci_zx_emmc_set_delay(struct dw_mci *host, unsigned int
>> delay,
>> + enum delay_type dflag)
>> +{
>> + struct dw_mci_zx_priv_data *priv = host->priv;
>> + struct regmap *sysc_base = priv->sysc_base;
>> + unsigned int clksel;
>> + unsigned int loop = 1000;
>> + int ret;
>> +
>> + if (!sysc_base)
>> + return -EINVAL;
>> +
>> + ret = regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
>> + PARA_HALF_CLK_MODE | PARA_DLL_BYPASS_MODE
>> |
>> + PARA_PHASE_DET_SEL_MASK |
>> + PARA_DLL_LOCK_NUM_MASK |
>> + DLL_REG_SET | PARA_DLL_START_MASK,
>> + PARA_DLL_START(4) |
>> PARA_DLL_LOCK_NUM(4));
>> + if (ret)
>> + return ret;
>> +
>> + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG1, &clksel);
>> + if (ret)
>> + return ret;
>> +
>> + if (dflag == DELAY_TYPE_CLK) {
>> + clksel &= ~CLK_SAMP_DELAY_MASK;
>> + clksel |= CLK_SAMP_DELAY(delay);
>> + } else {
>> + clksel &= ~READ_DQS_DELAY_MASK;
>> + clksel |= READ_DQS_DELAY(delay);
>> + }
>> +
>> + regmap_write(sysc_base, LB_AON_EMMC_CFG_REG1, clksel);
>> + regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
>> + PARA_DLL_START_MASK | PARA_DLL_LOCK_NUM_MASK |
>> + DLL_REG_SET,
>> + PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4) |
>> + DLL_REG_SET);
>> +
>> + do {
>> + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG2,
>> &clksel);
>> + if (ret)
>> + return ret;
>> +
>> + } while (--loop && !(clksel & ZX_DLL_LOCKED));
>> +
>> + if (!loop) {
>> + dev_err(host->dev, "Error: %s dll lock fail\n", __func__);
>> + return -EIO;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int dw_mci_zx_emmc_execute_tuning(struct dw_mci_slot *slot, u32
>> opcode)
>> +{
>> + struct dw_mci *host = slot->host;
>> + struct mmc_host *mmc = slot->mmc;
>> + int len, start = 0, end = 0, delay, best = 0;
>> +
>> + for (delay = 1 ; delay < 128; delay++) {
>> + dw_mci_zx_emmc_set_delay(host, delay, DELAY_TYPE_CLK);
>
>
> you never check if doing dw_mci_zx_emmc_set_delay successfully?
>
Set delay failure leads to tuning command failure. So failure case
will be reflected in tuning result.
>
>> + if (mmc_send_tuning(mmc, opcode, NULL)) {
>> + if (start >= 0) {
>> + end = delay - 1;
>> + /* check and update longest good range */
>> + if ((end - start) > len) {
>> + best = (start + end) >> 1;
>> + len = end - start;
>> + }
>> + }
>> + start = -1;
>> + end = 0;
>> + continue;
>> + }
>> + if (start < 0)
>> + start = delay;
>> + }
>> +
>> + if (start >= 0) {
>> + end = delay - 1;
>> + if ((end - start) > len) {
>> + best = (start + end) >> 1;
>> + len = end - start;
>> + }
>> + }
>> + if (best < 0)
>> + return -EIO;
>> +
>> + dev_info(host->dev, "%s best range: start %d end %d\n", __func__,
>> + start, end);
>> + dw_mci_zx_emmc_set_delay(host, best, DELAY_TYPE_CLK);
>
>
> ditto.
>
>
>> + return 0;
>> +}
>> +
>> +static int dw_mci_zx_prepare_hs400_tuning(struct dw_mci *host,
>> + struct mmc_ios *ios)
>> +{
>> + int ret;
>> +
>> + /* config phase shift as 90 degree */
>> + ret = dw_mci_zx_emmc_set_delay(host, 32, DELAY_TYPE_READ);
>> + if (ret < 0)
>> + return -EIO;
>> +
>> + return 0;
>> +}
>> +
>> +static int dw_mci_zx_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
>> +{
>> + struct dw_mci *host = slot->host;
>> +
>> + if (host->verid == 0x290a) /* only for emmc */
>> + return dw_mci_zx_emmc_execute_tuning(slot, opcode);
>> + /* TODO: Add 0x210a dedicated tuning for sd/sdio */
>> +
>> + return 0;
>> +}
>> +
>> +static int dw_mci_zx_parse_dt(struct dw_mci *host)
>> +{
>> + struct device_node *np = host->dev->of_node;
>> + struct device_node *node;
>> + struct dw_mci_zx_priv_data *priv;
>> + struct regmap *sysc_base;
>> + int ret;
>> +
>> + /* syscon is needed only by emmc */
>> + node = of_parse_phandle(np, "zte,aon-syscon", 0);
>> + if (node) {
>> + sysc_base = syscon_node_to_regmap(node);
>> + of_node_put(node);
>> +
>> + if (IS_ERR(sysc_base)) {
>> + ret = PTR_ERR(sysc_base);
>> + if (ret != -EPROBE_DEFER)
>> + dev_err(host->dev, "Can't get syscon:
>> %d\n",
>> + ret);
>> + return ret;
>> + }
>> + } else {
>> + return 0;
>> + }
>> +
>> + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
>> + if (!priv)
>> + return -ENOMEM;
>> + priv->sysc_base = sysc_base;
>> + host->priv = priv;
>> +
>> + return 0;
>> +}
>> +
>> +static unsigned long zx_dwmmc_caps[3] = {
>> + MMC_CAP_CMD23,
>> + MMC_CAP_CMD23,
>> + MMC_CAP_CMD23,
>> +};
>> +
>> +static const struct dw_mci_drv_data zx_drv_data = {
>> + .caps = zx_dwmmc_caps,
>> + .execute_tuning = dw_mci_zx_execute_tuning,
>> + .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning,
>> + .parse_dt = dw_mci_zx_parse_dt,
>> +};
>> +
>> +static const struct of_device_id dw_mci_zx_match[] = {
>> + { .compatible = "zte,zx296718-dw-mshc", .data = &zx_drv_data},
>> + {},
>> +};
>> +MODULE_DEVICE_TABLE(of, dw_mci_zx_match);
>> +
>> +static int dw_mci_zx_probe(struct platform_device *pdev)
>> +{
>> + const struct dw_mci_drv_data *drv_data;
>> + const struct of_device_id *match;
>> +
>> + match = of_match_node(dw_mci_zx_match, pdev->dev.of_node);
>> + drv_data = match->data;
>> +
>> + return dw_mci_pltfm_register(pdev, drv_data);
>> +}
>> +
>> +static const struct dev_pm_ops dw_mci_zx_dev_pm_ops = {
>> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
>> + pm_runtime_force_resume)
>> + SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
>> + dw_mci_runtime_resume,
>> + NULL)
>> +};
>> +
>> +static struct platform_driver dw_mci_zx_pltfm_driver = {
>> + .probe = dw_mci_zx_probe,
>> + .remove = dw_mci_pltfm_remove,
>> + .driver = {
>> + .name = "dwmmc_zx",
>> + .of_match_table = dw_mci_zx_match,
>> + .pm = &dw_mci_zx_dev_pm_ops,
>> + },
>> +};
>> +
>> +module_platform_driver(dw_mci_zx_pltfm_driver);
>> +
>> +MODULE_DESCRIPTION("ZTE emmc/sd driver");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/drivers/mmc/host/dw_mmc-zx.h b/drivers/mmc/host/dw_mmc-zx.h
>> new file mode 100644
>> index 0000000..f369997
>> --- /dev/null
>> +++ b/drivers/mmc/host/dw_mmc-zx.h
>> @@ -0,0 +1,31 @@
>> +#ifndef _DW_MMC_ZX_H_
>> +#define _DW_MMC_ZX_H_
>> +
>> +/* ZX296718 SoC specific DLL register offset. */
>> +#define LB_AON_EMMC_CFG_REG0 0x1B0
>> +#define LB_AON_EMMC_CFG_REG1 0x1B4
>> +#define LB_AON_EMMC_CFG_REG2 0x1B8
>> +
>> +/* LB_AON_EMMC_CFG_REG0 register defines */
>> +#define PARA_DLL_START(x) ((x) & 0xFF)
>> +#define PARA_DLL_START_MASK 0xFF
>> +#define DLL_REG_SET BIT(8)
>> +#define PARA_DLL_LOCK_NUM(x) (((x) & 7) << 16)
>> +#define PARA_DLL_LOCK_NUM_MASK (7 << 16)
>> +#define PARA_PHASE_DET_SEL(x) (((x) & 7) << 20)
>> +#define PARA_PHASE_DET_SEL_MASK (7 << 20)
>> +#define PARA_DLL_BYPASS_MODE BIT(23)
>> +#define PARA_HALF_CLK_MODE BIT(24)
>> +
>> +/* LB_AON_EMMC_CFG_REG1 register defines */
>> +#define READ_DQS_DELAY(x) ((x) & 0x7F)
>> +#define READ_DQS_DELAY_MASK (0x7F)
>> +#define READ_DQS_BYPASS_MODE BIT(7)
>> +#define CLK_SAMP_DELAY(x) (((x) & 0x7F) << 8)
>> +#define CLK_SAMP_DELAY_MASK (0x7F << 8)
>> +#define CLK_SAMP_BYPASS_MODE BIT(15)
>> +
>> +/* LB_AON_EMMC_CFG_REG2 register defines */
>> +#define ZX_DLL_LOCKED BIT(2)
>> +
>> +#endif /* _DW_MMC_ZX_H_ */
>>
>
>
> --
> Best Regards
> Shawn Lin
>
^ permalink raw reply
* RE: [PATCH v2] mmc: sdhci-of-esdhc: fixup PRESENT_STATE read
From: Michael Walle @ 2016-11-14 8:50 UTC (permalink / raw)
To: Y.B. Lu; +Cc: linux-kernel, linux-mmc, Ulf Hansson, Adrian Hunter, yangbo lu
In-Reply-To: <DB6PR0401MB2536FBC12CD47AED152F4783F8BC0@DB6PR0401MB2536.eurprd04.prod.outlook.com>
Am 2016-11-14 04:00, schrieb Y.B. Lu:
>> -----Original Message-----
>> From: Michael Walle [mailto:michael@walle.cc]
>> Sent: Saturday, November 12, 2016 12:04 AM
>> To: linux-kernel@vger.kernel.org
>> Cc: linux-mmc@vger.kernel.org; Ulf Hansson; Adrian Hunter; yangbo lu;
>> Michael Walle
>> Subject: [PATCH v2] mmc: sdhci-of-esdhc: fixup PRESENT_STATE read
>>
>> Since commit 87a18a6a5652 ("mmc: mmc: Use ->card_busy() to detect busy
>> cards in __mmc_switch()") the ESDHC driver is broken:
>> mmc0: Card stuck in programming state! __mmc_switch
>> mmc0: error -110 whilst initialising MMC card
>>
>> Since this commit __mmc_switch() uses ->card_busy(), which is
>> sdhci_card_busy() for the esdhc driver. sdhci_card_busy() uses the
>> PRESENT_STATE register, specifically the DAT0 signal level bit. But
>> the
>> ESDHC uses a non-conformant PRESENT_STATE register, thus a read fixup
>> is
>> required to make the driver work again.
>>
>> Signed-off-by: Michael Walle <michael@walle.cc>
>> Fixes: 87a18a6a5652 ("mmc: mmc: Use ->card_busy() to detect busy cards
>> in
>> __mmc_switch()")
>> ---
>> v2:
>> - use lower bits of the original value (that was actually a typo)
>> - add fixes tag
>> - fix typo
>>
>> drivers/mmc/host/sdhci-of-esdhc.c | 12 ++++++++++++
>> 1 file changed, 12 insertions(+)
>>
>> diff --git a/drivers/mmc/host/sdhci-of-esdhc.c
>> b/drivers/mmc/host/sdhci-
>> of-esdhc.c
>> index fb71c86..f9c84bb 100644
>> --- a/drivers/mmc/host/sdhci-of-esdhc.c
>> +++ b/drivers/mmc/host/sdhci-of-esdhc.c
>> @@ -66,6 +66,18 @@ static u32 esdhc_readl_fixup(struct sdhci_host
>> *host,
>> return ret;
>> }
>> }
>> + /*
>> + * The DAT[3:0] line signal levels and the CMD line signal level is
>> + * not compatible with standard SDHC register. Move the
>> corresponding
>> + * bits around.
>> + */
>> + if (spec_reg == SDHCI_PRESENT_STATE) {
>> + ret = value & ~0xf8000000;
>
> [Lu Yangbo-B47093] I think the bits which should be cleaned before
> following '|=' are 0x01f00000 not 0xf8000000, right?
> :)
Its neither 0x01f00000 nor 0xf8000000 :( I'll put the bits definition
into the comment the next time, so everyone can review them. bit[31:24]
are the line DAT[7:0] line signal level. bit[23] is command signal
level. All other bits are the same as in the standard SDHC PRESENT_STATE
register.
I want to keep all but the upper 9 bits from the original value,
therefore, this should be the correct mask:
ret = value & ~0xff800000;
-michael
>
>> + ret |= (value >> 4) & SDHCI_DATA_LVL_MASK;
>> + ret |= (value << 1) & 0x01000000;
>> + return ret;
>> + }
>> +
>> ret = value;
>> return ret;
>> }
>> --
>> 2.1.4
^ permalink raw reply
* Re: [PATCH v5 4/5] mmc: dw: Add fifo address property
From: Shawn Lin @ 2016-11-14 8:12 UTC (permalink / raw)
To: Jun Nie, shawn.guo, xie.baoyou
Cc: shawn.lin, ulf.hansson, jh80.chung, jason.liu, linux-mmc
In-Reply-To: <1478568298-18380-5-git-send-email-jun.nie@linaro.org>
On 2016/11/8 9:24, Jun Nie wrote:
> The FIFO address may break default address assumption of 0x100
> (version < 0x240A) and 0x200(version >= 0x240A) in current driver.
> The new property is introduced to override fifo address via DT
> node information.
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> ---
> drivers/mmc/host/dw_mmc.c | 6 +++++-
> include/linux/mmc/dw_mmc.h | 2 ++
> 2 files changed, 7 insertions(+), 1 deletion(-)
>
Looks good to me,
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 1c9ee36..696b5e6 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -2955,6 +2955,8 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>
> of_property_read_u32(np, "card-detect-delay", &pdata->detect_delay_ms);
>
> + of_property_read_u32(np, "data-addr", &host->data_addr_override);
> +
> if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
> pdata->bus_hz = clock_frequency;
>
> @@ -3158,7 +3160,9 @@ int dw_mci_probe(struct dw_mci *host)
> host->verid = SDMMC_GET_VERID(mci_readl(host, VERID));
> dev_info(host->dev, "Version ID is %04x\n", host->verid);
>
> - if (host->verid < DW_MMC_240A)
> + if (host->data_addr_override)
> + host->fifo_reg = host->regs + host->data_addr_override;
> + else if (host->verid < DW_MMC_240A)
> host->fifo_reg = host->regs + DATA_OFFSET;
> else
> host->fifo_reg = host->regs + DATA_240A_OFFSET;
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index f5af2bd..17cb95a 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -107,6 +107,7 @@ struct dw_mci_dma_slave {
> * @ciu_clk: Pointer to card interface unit clock instance.
> * @slot: Slots sharing this MMC controller.
> * @fifo_depth: depth of FIFO.
> + * @data_addr_override: override fifo reg offset with this value.
> * @data_shift: log2 of FIFO item size.
> * @part_buf_start: Start index in part_buf.
> * @part_buf_count: Bytes of partial data in part_buf.
> @@ -154,6 +155,7 @@ struct dw_mci {
> spinlock_t irq_lock;
> void __iomem *regs;
> void __iomem *fifo_reg;
> + u32 data_addr_override;
>
> struct scatterlist *sg;
> struct sg_mapping_iter sg_miter;
>
--
Best Regards
Shawn Lin
^ permalink raw reply
* Re: [PATCH v5 5/5] mmc: dw: Add fifo watermark alignment property
From: Shawn Lin @ 2016-11-14 8:10 UTC (permalink / raw)
To: Jun Nie, shawn.guo, xie.baoyou
Cc: shawn.lin, ulf.hansson, jh80.chung, jason.liu, linux-mmc
In-Reply-To: <1478568298-18380-6-git-send-email-jun.nie@linaro.org>
On 2016/11/8 9:24, Jun Nie wrote:
> Data done irq is expected if data length is less than
> watermark in PIO mode. But fifo watermark is requested
> to be aligned with data length in some SoC so that TX/RX
> irq can be generated with data done irq. Add the
> watermark alignment to mark this requirement and force
> fifo watermark setting accordingly.
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> ---
> drivers/mmc/host/dw_mmc.c | 11 +++++++++--
> include/linux/mmc/dw_mmc.h | 3 +++
> 2 files changed, 12 insertions(+), 2 deletions(-)
>
Reviewed-by: Shawn Lin <shawn.lin@rock-chips.com>
> diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
> index 696b5e6..6d85ca6 100644
> --- a/drivers/mmc/host/dw_mmc.c
> +++ b/drivers/mmc/host/dw_mmc.c
> @@ -1111,11 +1111,15 @@ static void dw_mci_submit_data(struct dw_mci *host, struct mmc_data *data)
> mci_writel(host, CTRL, temp);
>
> /*
> - * Use the initial fifoth_val for PIO mode.
> + * Use the initial fifoth_val for PIO mode. If wm_algined
> + * is set, we set watermark same as data size.
> * If next issued data may be transfered by DMA mode,
> * prev_blksz should be invalidated.
> */
> - mci_writel(host, FIFOTH, host->fifoth_val);
> + if (host->wm_aligned)
> + dw_mci_adjust_fifoth(host, data);
> + else
> + mci_writel(host, FIFOTH, host->fifoth_val);
> host->prev_blksz = 0;
> } else {
> /*
> @@ -2957,6 +2961,9 @@ static struct dw_mci_board *dw_mci_parse_dt(struct dw_mci *host)
>
> of_property_read_u32(np, "data-addr", &host->data_addr_override);
>
> + if (of_get_property(np, "fifo-watermark-aligned", NULL))
> + host->wm_aligned = true;
> +
> if (!of_property_read_u32(np, "clock-frequency", &clock_frequency))
> pdata->bus_hz = clock_frequency;
>
> diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
> index 17cb95a..ee4bb30 100644
> --- a/include/linux/mmc/dw_mmc.h
> +++ b/include/linux/mmc/dw_mmc.h
> @@ -108,6 +108,8 @@ struct dw_mci_dma_slave {
> * @slot: Slots sharing this MMC controller.
> * @fifo_depth: depth of FIFO.
> * @data_addr_override: override fifo reg offset with this value.
> + * @wm_aligned: force fifo watermark equal with data length in PIO mode.
> + * Set as true if alignment is needed.
> * @data_shift: log2 of FIFO item size.
> * @part_buf_start: Start index in part_buf.
> * @part_buf_count: Bytes of partial data in part_buf.
> @@ -156,6 +158,7 @@ struct dw_mci {
> void __iomem *regs;
> void __iomem *fifo_reg;
> u32 data_addr_override;
> + bool wm_aligned;
>
> struct scatterlist *sg;
> struct sg_mapping_iter sg_miter;
>
--
Best Regards
Shawn Lin
^ permalink raw reply
* Re: [PATCH v5 2/5] mmc: zx: Initial support for ZX mmc controller
From: Shawn Lin @ 2016-11-14 8:07 UTC (permalink / raw)
To: Jun Nie, shawn.guo, xie.baoyou
Cc: shawn.lin, ulf.hansson, jh80.chung, jason.liu, linux-mmc
In-Reply-To: <1478568298-18380-3-git-send-email-jun.nie@linaro.org>
Hi, Jun,
Mostly it looks fine but some minor nits.
On 2016/11/8 9:24, Jun Nie wrote:
> This platform driver adds initial support for the DW host controller
> found on ZTE SoCs.
>
> It has been tested on ZX296718 EVB board currently. More support on
> timing tuning will be added when hardware is available.
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> ---
> drivers/mmc/host/Kconfig | 9 ++
> drivers/mmc/host/Makefile | 1 +
> drivers/mmc/host/dw_mmc-zx.c | 243 +++++++++++++++++++++++++++++++++++++++++++
> drivers/mmc/host/dw_mmc-zx.h | 31 ++++++
> 4 files changed, 284 insertions(+)
> create mode 100644 drivers/mmc/host/dw_mmc-zx.c
> create mode 100644 drivers/mmc/host/dw_mmc-zx.h
>
> diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
> index 5274f50..4dafbc2 100644
> --- a/drivers/mmc/host/Kconfig
> +++ b/drivers/mmc/host/Kconfig
> @@ -662,6 +662,15 @@ config MMC_DW_ROCKCHIP
> Synopsys DesignWare Memory Card Interface driver. Select this option
> for platforms based on RK3066, RK3188 and RK3288 SoC's.
>
> +config MMC_DW_ZX
> + tristate "ZTE specific extensions for Synopsys DW Memory Card Interface"
> + depends on MMC_DW && ARCH_ZX
> + select MMC_DW_PLTFM
> + help
> + This selects support for ZTE SoC specific extensions to the
> + Synopsys DesignWare Memory Card Interface driver. Select this option
> + for platforms based on ZX296718 SoC's.
> +
> config MMC_SH_MMCIF
> tristate "SuperH Internal MMCIF support"
> depends on HAS_DMA
> diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
> index e2bdaaf..9766143 100644
> --- a/drivers/mmc/host/Makefile
> +++ b/drivers/mmc/host/Makefile
> @@ -48,6 +48,7 @@ obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o
> obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o
> obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o
> obj-$(CONFIG_MMC_DW_ROCKCHIP) += dw_mmc-rockchip.o
> +obj-$(CONFIG_MMC_DW_ZX) += dw_mmc-zx.o
> obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o
> obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o
> obj-$(CONFIG_MMC_VUB300) += vub300.o
> diff --git a/drivers/mmc/host/dw_mmc-zx.c b/drivers/mmc/host/dw_mmc-zx.c
> new file mode 100644
> index 0000000..c48d851
> --- /dev/null
> +++ b/drivers/mmc/host/dw_mmc-zx.c
> @@ -0,0 +1,243 @@
> +/*
> + * ZX Specific Extensions for Synopsys DW Multimedia Card Interface driver
> + *
> + * Copyright (C) 2016, Linaro Ltd.
> + * Copyright (C) 2016, ZTE Corp.
> + *
> + * 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/mfd/syscon.h>
> +#include <linux/mmc/dw_mmc.h>
> +#include <linux/mmc/host.h>
> +#include <linux/mmc/mmc.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/platform_device.h>
> +#include <linux/pm_runtime.h>
> +#include <linux/regmap.h>
> +#include <linux/slab.h>
> +
> +#include "dw_mmc.h"
> +#include "dw_mmc-pltfm.h"
> +#include "dw_mmc-zx.h"
> +
> +struct dw_mci_zx_priv_data {
> + struct regmap *sysc_base;
> +};
> +
> +enum delay_type {
> + DELAY_TYPE_READ, /* read dqs delay */
> + DELAY_TYPE_CLK, /* clk sample delay */
> +};
> +
> +static int dw_mci_zx_emmc_set_delay(struct dw_mci *host, unsigned int delay,
> + enum delay_type dflag)
> +{
> + struct dw_mci_zx_priv_data *priv = host->priv;
> + struct regmap *sysc_base = priv->sysc_base;
> + unsigned int clksel;
> + unsigned int loop = 1000;
> + int ret;
> +
> + if (!sysc_base)
> + return -EINVAL;
> +
> + ret = regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
> + PARA_HALF_CLK_MODE | PARA_DLL_BYPASS_MODE |
> + PARA_PHASE_DET_SEL_MASK |
> + PARA_DLL_LOCK_NUM_MASK |
> + DLL_REG_SET | PARA_DLL_START_MASK,
> + PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4));
> + if (ret)
> + return ret;
> +
> + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG1, &clksel);
> + if (ret)
> + return ret;
> +
> + if (dflag == DELAY_TYPE_CLK) {
> + clksel &= ~CLK_SAMP_DELAY_MASK;
> + clksel |= CLK_SAMP_DELAY(delay);
> + } else {
> + clksel &= ~READ_DQS_DELAY_MASK;
> + clksel |= READ_DQS_DELAY(delay);
> + }
> +
> + regmap_write(sysc_base, LB_AON_EMMC_CFG_REG1, clksel);
> + regmap_update_bits(sysc_base, LB_AON_EMMC_CFG_REG0,
> + PARA_DLL_START_MASK | PARA_DLL_LOCK_NUM_MASK |
> + DLL_REG_SET,
> + PARA_DLL_START(4) | PARA_DLL_LOCK_NUM(4) |
> + DLL_REG_SET);
> +
> + do {
> + ret = regmap_read(sysc_base, LB_AON_EMMC_CFG_REG2, &clksel);
> + if (ret)
> + return ret;
> +
> + } while (--loop && !(clksel & ZX_DLL_LOCKED));
> +
> + if (!loop) {
> + dev_err(host->dev, "Error: %s dll lock fail\n", __func__);
> + return -EIO;
> + }
> +
> + return 0;
> +}
> +
> +static int dw_mci_zx_emmc_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
> +{
> + struct dw_mci *host = slot->host;
> + struct mmc_host *mmc = slot->mmc;
> + int len, start = 0, end = 0, delay, best = 0;
> +
> + for (delay = 1 ; delay < 128; delay++) {
> + dw_mci_zx_emmc_set_delay(host, delay, DELAY_TYPE_CLK);
you never check if doing dw_mci_zx_emmc_set_delay successfully?
> + if (mmc_send_tuning(mmc, opcode, NULL)) {
> + if (start >= 0) {
> + end = delay - 1;
> + /* check and update longest good range */
> + if ((end - start) > len) {
> + best = (start + end) >> 1;
> + len = end - start;
> + }
> + }
> + start = -1;
> + end = 0;
> + continue;
> + }
> + if (start < 0)
> + start = delay;
> + }
> +
> + if (start >= 0) {
> + end = delay - 1;
> + if ((end - start) > len) {
> + best = (start + end) >> 1;
> + len = end - start;
> + }
> + }
> + if (best < 0)
> + return -EIO;
> +
> + dev_info(host->dev, "%s best range: start %d end %d\n", __func__,
> + start, end);
> + dw_mci_zx_emmc_set_delay(host, best, DELAY_TYPE_CLK);
ditto.
> + return 0;
> +}
> +
> +static int dw_mci_zx_prepare_hs400_tuning(struct dw_mci *host,
> + struct mmc_ios *ios)
> +{
> + int ret;
> +
> + /* config phase shift as 90 degree */
> + ret = dw_mci_zx_emmc_set_delay(host, 32, DELAY_TYPE_READ);
> + if (ret < 0)
> + return -EIO;
> +
> + return 0;
> +}
> +
> +static int dw_mci_zx_execute_tuning(struct dw_mci_slot *slot, u32 opcode)
> +{
> + struct dw_mci *host = slot->host;
> +
> + if (host->verid == 0x290a) /* only for emmc */
> + return dw_mci_zx_emmc_execute_tuning(slot, opcode);
> + /* TODO: Add 0x210a dedicated tuning for sd/sdio */
> +
> + return 0;
> +}
> +
> +static int dw_mci_zx_parse_dt(struct dw_mci *host)
> +{
> + struct device_node *np = host->dev->of_node;
> + struct device_node *node;
> + struct dw_mci_zx_priv_data *priv;
> + struct regmap *sysc_base;
> + int ret;
> +
> + /* syscon is needed only by emmc */
> + node = of_parse_phandle(np, "zte,aon-syscon", 0);
> + if (node) {
> + sysc_base = syscon_node_to_regmap(node);
> + of_node_put(node);
> +
> + if (IS_ERR(sysc_base)) {
> + ret = PTR_ERR(sysc_base);
> + if (ret != -EPROBE_DEFER)
> + dev_err(host->dev, "Can't get syscon: %d\n",
> + ret);
> + return ret;
> + }
> + } else {
> + return 0;
> + }
> +
> + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> + priv->sysc_base = sysc_base;
> + host->priv = priv;
> +
> + return 0;
> +}
> +
> +static unsigned long zx_dwmmc_caps[3] = {
> + MMC_CAP_CMD23,
> + MMC_CAP_CMD23,
> + MMC_CAP_CMD23,
> +};
> +
> +static const struct dw_mci_drv_data zx_drv_data = {
> + .caps = zx_dwmmc_caps,
> + .execute_tuning = dw_mci_zx_execute_tuning,
> + .prepare_hs400_tuning = dw_mci_zx_prepare_hs400_tuning,
> + .parse_dt = dw_mci_zx_parse_dt,
> +};
> +
> +static const struct of_device_id dw_mci_zx_match[] = {
> + { .compatible = "zte,zx296718-dw-mshc", .data = &zx_drv_data},
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, dw_mci_zx_match);
> +
> +static int dw_mci_zx_probe(struct platform_device *pdev)
> +{
> + const struct dw_mci_drv_data *drv_data;
> + const struct of_device_id *match;
> +
> + match = of_match_node(dw_mci_zx_match, pdev->dev.of_node);
> + drv_data = match->data;
> +
> + return dw_mci_pltfm_register(pdev, drv_data);
> +}
> +
> +static const struct dev_pm_ops dw_mci_zx_dev_pm_ops = {
> + SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
> + pm_runtime_force_resume)
> + SET_RUNTIME_PM_OPS(dw_mci_runtime_suspend,
> + dw_mci_runtime_resume,
> + NULL)
> +};
> +
> +static struct platform_driver dw_mci_zx_pltfm_driver = {
> + .probe = dw_mci_zx_probe,
> + .remove = dw_mci_pltfm_remove,
> + .driver = {
> + .name = "dwmmc_zx",
> + .of_match_table = dw_mci_zx_match,
> + .pm = &dw_mci_zx_dev_pm_ops,
> + },
> +};
> +
> +module_platform_driver(dw_mci_zx_pltfm_driver);
> +
> +MODULE_DESCRIPTION("ZTE emmc/sd driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/mmc/host/dw_mmc-zx.h b/drivers/mmc/host/dw_mmc-zx.h
> new file mode 100644
> index 0000000..f369997
> --- /dev/null
> +++ b/drivers/mmc/host/dw_mmc-zx.h
> @@ -0,0 +1,31 @@
> +#ifndef _DW_MMC_ZX_H_
> +#define _DW_MMC_ZX_H_
> +
> +/* ZX296718 SoC specific DLL register offset. */
> +#define LB_AON_EMMC_CFG_REG0 0x1B0
> +#define LB_AON_EMMC_CFG_REG1 0x1B4
> +#define LB_AON_EMMC_CFG_REG2 0x1B8
> +
> +/* LB_AON_EMMC_CFG_REG0 register defines */
> +#define PARA_DLL_START(x) ((x) & 0xFF)
> +#define PARA_DLL_START_MASK 0xFF
> +#define DLL_REG_SET BIT(8)
> +#define PARA_DLL_LOCK_NUM(x) (((x) & 7) << 16)
> +#define PARA_DLL_LOCK_NUM_MASK (7 << 16)
> +#define PARA_PHASE_DET_SEL(x) (((x) & 7) << 20)
> +#define PARA_PHASE_DET_SEL_MASK (7 << 20)
> +#define PARA_DLL_BYPASS_MODE BIT(23)
> +#define PARA_HALF_CLK_MODE BIT(24)
> +
> +/* LB_AON_EMMC_CFG_REG1 register defines */
> +#define READ_DQS_DELAY(x) ((x) & 0x7F)
> +#define READ_DQS_DELAY_MASK (0x7F)
> +#define READ_DQS_BYPASS_MODE BIT(7)
> +#define CLK_SAMP_DELAY(x) (((x) & 0x7F) << 8)
> +#define CLK_SAMP_DELAY_MASK (0x7F << 8)
> +#define CLK_SAMP_BYPASS_MODE BIT(15)
> +
> +/* LB_AON_EMMC_CFG_REG2 register defines */
> +#define ZX_DLL_LOCKED BIT(2)
> +
> +#endif /* _DW_MMC_ZX_H_ */
>
--
Best Regards
Shawn Lin
^ permalink raw reply
* Re: [PATCH v5 1/5] mmc: dt-bindings: add ZTE ZX296718 MMC bindings
From: Shawn Lin @ 2016-11-14 7:58 UTC (permalink / raw)
To: Jun Nie, shawn.guo, xie.baoyou
Cc: shawn.lin, ulf.hansson, jh80.chung, jason.liu, linux-mmc
In-Reply-To: <1478568298-18380-2-git-send-email-jun.nie@linaro.org>
On 2016/11/8 9:24, Jun Nie wrote:
> Document the device-tree binding of ZTE MMC host on
> ZX296718 SoC.
>
> Signed-off-by: Jun Nie <jun.nie@linaro.org>
> ---
> .../devicetree/bindings/mmc/zx-dw-mshc.txt | 35 ++++++++++++++++++++++
> 1 file changed, 35 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
>
> diff --git a/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
> new file mode 100644
> index 0000000..c175c4b
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/mmc/zx-dw-mshc.txt
> @@ -0,0 +1,35 @@
> +* ZTE specific extensions to the Synopsys Designware Mobile Storage
> + Host Controller
> +
> +The Synopsys designware mobile storage host controller is used to interface
> +a SoC with storage medium such as eMMC or SD/MMC cards. This file documents
> +differences between the core Synopsys dw mshc controller properties described
> +by synopsys-dw-mshc.txt and the properties used by the ZTE specific
> +extensions to the Synopsys Designware Mobile Storage Host Controller.
> +
> +Required Properties:
> +
> +* compatible: should be
> + - "zte,zx296718-dw-mshc": for ZX SoCs
> +
> +Example:
> +
> + mmc1: mmc@1110000 {
> + compatible = "zte,zx296718-dw-mshc";
> + #address-cells = <1>;
> + #size-cells = <0>;
> + reg = <0x01110000 0x1000>;
> + interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
> + fifo-depth = <32>;
> + data-addr = <0x200>;
> + fifo-watermark-aligned;
> + bus-width = <4>;
> + clock-frequency = <50000000>;
do you need both clock-frequency and max-frequency here?
> + clocks = <&topcrm SD0_AHB>, <&topcrm SD0_WCLK>;
> + clock-names = "biu", "ciu";
> + num-slots = <1>;
> + max-frequency = <50000000>;
> + cap-sdio-irq;
> + cap-sd-highspeed;
> + status = "disabled";
> + };
>
--
Best Regards
Shawn Lin
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox