Message ID | 1386770541-15056-3-git-send-email-zhangfei.gao@linaro.org |
---|---|
State | Changes Requested |
Headers | show |
On Wednesday 11 December 2013, Zhangfei Gao wrote: > Add dw_mmc-k3.c for k3v2, support sd/emmc > > Signed-off-by: Zhangfei Gao <zhangfei.gao@linaro.org> > Tested-by: Zhigang Wang <brooke.wangzhigang@huawei.com> > --- > .../devicetree/bindings/mmc/k3-dw-mshc.txt | 51 ++++++++ > drivers/mmc/host/Kconfig | 10 ++ > drivers/mmc/host/Makefile | 1 + > drivers/mmc/host/dw_mmc-k3.c | 136 ++++++++++++++++++++ > 4 files changed, 198 insertions(+) > create mode 100644 Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt > create mode 100644 drivers/mmc/host/dw_mmc-k3.c > > diff --git a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt > new file mode 100644 > index 000000000000..d816b89c386a > --- /dev/null > +++ b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt > @@ -0,0 +1,51 @@ > +* Hisilicon specific extensions to the Synopsys Designware Mobile > + Storage Host Controller > + > +Read synopsys-dw-mshc.txt for more details > + > +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 Hisilicon specific > +extensions to the Synopsys Designware Mobile Storage Host Controller. > + > +Required Properties: > + > +* compatible: should be one of the following. > + - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extentions. > +* clk-table-num: should be number of clks in clk-table required by each mmc timing > +* clk-table: should clock list required by each mmc timing I have not seen "clk-table" and "clk-table-num" before. Are these standard properties? What are the units that are used here, what does the index mean? Arnd
On 12/11/2013 10:49 PM, Arnd Bergmann wrote: > On Wednesday 11 December 2013, Zhangfei Gao wrote: >> +Required Properties: >> + >> +* compatible: should be one of the following. >> + - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extentions. >> +* clk-table-num: should be number of clks in clk-table required by each mmc timing >> +* clk-table: should clock list required by each mmc timing > > I have not seen "clk-table" and "clk-table-num" before. Are these standard > properties? What are the units that are used here, what does the index mean? > "clk-table" and "clk-table-num" are private properties. Instead simply on/off, the ip need different ciu clock for each timing mode. Take emmc as example, clk-table-num = <8>; clk-table = <13000000 50000000 0 0 13000000 50000000 0 100000000>; MMC_TIMING_LEGACY mode, 25M should be set with parent clock 180M, MMC_TIMING_MMC_HS mode, 50M is required with parent clock 360M "clk-table" list all clocks to be set in all supported timing one by one. "clk-table-num" is the table number, since not find function getting table number. For example, next version will support MMC_TIMING_MMC_HS200 mode, the clk-table-num = <9> with 9 clocks in the "clk-table" Thanks
On 12/11/2013 11:36 PM, zhangfei wrote: > > > On 12/11/2013 10:49 PM, Arnd Bergmann wrote: >> On Wednesday 11 December 2013, Zhangfei Gao wrote: > >>> +Required Properties: >>> + >>> +* compatible: should be one of the following. >>> + - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific >>> extentions. >>> +* clk-table-num: should be number of clks in clk-table required by >>> each mmc timing >>> +* clk-table: should clock list required by each mmc timing >> >> I have not seen "clk-table" and "clk-table-num" before. Are these >> standard >> properties? What are the units that are used here, what does the index >> mean? >> > > "clk-table" and "clk-table-num" are private properties. > Instead simply on/off, the ip need different ciu clock for each timing > mode. > Take emmc as example, > clk-table-num = <8>; > clk-table = My bad, this is for sd. > <13000000 50000000 0 0 13000000 50000000 0 100000000>; <25000000 0 50000000 25000000 50000000 100000000 0 50000000>; > MMC_TIMING_LEGACY mode, 25M should be set with parent clock 180M, > MMC_TIMING_MMC_HS mode, 50M is required with parent clock 360M > > "clk-table" list all clocks to be set in all supported timing one by one. > "clk-table-num" is the table number, since not find function getting > table number. > For example, next version will support MMC_TIMING_MMC_HS200 mode, the > clk-table-num = <9> with 9 clocks in the "clk-table" > > Thanks > >
On Wednesday 11 December 2013, zhangfei wrote: > > > > I have not seen "clk-table" and "clk-table-num" before. Are these standard > > properties? What are the units that are used here, what does the index mean? > > > > "clk-table" and "clk-table-num" are private properties. > Instead simply on/off, the ip need different ciu clock for each timing mode. But aren't the times fixed for each mode? Why do you need to specify them in the DT? I would expect that the clock rates for each mode are set in the MMC and SD specifications. When you call clk_set_rate(), it should normally be enough to ask for the clock you actually want and let the clk subsystem figure out how to set up the parents and multipliers on the way. > Take emmc as example, > clk-table-num = <8>; > clk-table = > <13000000 50000000 0 0 13000000 50000000 0 100000000>; > MMC_TIMING_LEGACY mode, 25M should be set with parent clock 180M, > MMC_TIMING_MMC_HS mode, 50M is required with parent clock 360M > > "clk-table" list all clocks to be set in all supported timing one by one. > "clk-table-num" is the table number, since not find function getting > table number. > For example, next version will support MMC_TIMING_MMC_HS200 mode, the > clk-table-num = <9> with 9 clocks in the "clk-table" If you have a property with an array, you can use of_find_property() to get to the 'struct property' and then read the 'length' member of that struct, or you can use of_property_for_each_u32() to iterate through each value. While I still hope that you don't even need this array as per the reasoning above, if you actually need it, you should specify exactly what each value means, such as 1. CIU clock rate in HZ for 20MHz SPI mode operation 2. CIU clock rate in HZ for 25MHz SD card operation 3. CIU clock rate in HZ for 26MHz MMC card operation 4. CIU clock rate in HZ for 50MHz SD card operation ... Arnd
Dear Arnd On 12/12/2013 04:12 AM, Arnd Bergmann wrote: > On Wednesday 11 December 2013, zhangfei wrote: >>> >>> I have not seen "clk-table" and "clk-table-num" before. Are these standard >>> properties? What are the units that are used here, what does the index mean? >>> >> >> "clk-table" and "clk-table-num" are private properties. >> Instead simply on/off, the ip need different ciu clock for each timing mode. > > But aren't the times fixed for each mode? Why do you need to specify them in > the DT? I would expect that the clock rates for each mode are set in the > MMC and SD specifications. When you call clk_set_rate(), it should normally > be enough to ask for the clock you actually want and let the clk subsystem > figure out how to set up the parents and multipliers on the way. Yes. that's will be perfect. However, currently this ip still has no such capability. 1. Input rate for init are diferent for different controller, not the init 400K, some are 13M, others are 25M, since different clock source. This can be easily solved by clock-freq-init = <25000000> 2. There is maxmum limit, also can be easily solved by define CLK_MAX. 3. However some mode can not use the max speed from ios->clock for example UHS_SDR104_MAX_DTR 208000000 can not be used, only half may be reached, at least currently. > >> Take emmc as example, >> clk-table-num = <8>; >> clk-table = >> <13000000 50000000 0 0 13000000 50000000 0 100000000>; >> MMC_TIMING_LEGACY mode, 25M should be set with parent clock 180M, >> MMC_TIMING_MMC_HS mode, 50M is required with parent clock 360M >> >> "clk-table" list all clocks to be set in all supported timing one by one. >> "clk-table-num" is the table number, since not find function getting >> table number. >> For example, next version will support MMC_TIMING_MMC_HS200 mode, the >> clk-table-num = <9> with 9 clocks in the "clk-table" > > If you have a property with an array, you can use of_find_property() > to get to the 'struct property' and then read the 'length' member > of that struct, or you can use of_property_for_each_u32() to iterate > through each value. Great, this works. > > While I still hope that you don't even need this array as per the reasoning > above, if you actually need it, you should specify exactly what each > value means, such as > > 1. CIU clock rate in HZ for 20MHz SPI mode operation > 2. CIU clock rate in HZ for 25MHz SD card operation > 3. CIU clock rate in HZ for 26MHz MMC card operation > 4. CIU clock rate in HZ for 50MHz SD card operation > ... How about this desc * clock-freq-table: should be the frequency (in Hz) array of the ciu clock in each supported timing. 1. CIU clock rate in HZ for MMC_TIMING_LEGACY mode 2. CIU clock rate in HZ for MMC_TIMING_MMC_HS mode 3. CIU clock rate in HZ for MMC_TIMING_SD_HS mode 4. CIU clock rate in HZ for MMC_TIMING_UHS_SDR12 mode 5. CIU clock rate in HZ for MMC_TIMING_UHS_SDR25 mode 6. CIU clock rate in HZ for MMC_TIMING_UHS_SDR50 mode 7. CIU clock rate in HZ for MMC_TIMING_UHS_SDR104 mode 8. CIU clock rate in HZ for MMC_TIMING_SD_HS mode 9. CIU clock rate in HZ for MMC_TIMING_MMC_HS200 mode Thanks
On Thursday 12 December 2013, zhangfei wrote: > On 12/12/2013 04:12 AM, Arnd Bergmann wrote: > > On Wednesday 11 December 2013, zhangfei wrote: > > > > But aren't the times fixed for each mode? Why do you need to specify them in > > the DT? I would expect that the clock rates for each mode are set in the > > MMC and SD specifications. When you call clk_set_rate(), it should normally > > be enough to ask for the clock you actually want and let the clk subsystem > > figure out how to set up the parents and multipliers on the way. > > Yes. that's will be perfect. > > However, currently this ip still has no such capability. > Input rate for init are diferent for different controller, not the > init 400K, some are 13M, others are 25M, since different clock source. > This can be easily solved by clock-freq-init = <25000000> > 2. There is maxmum limit, also can be easily solved by define CLK_MAX. > 3. However some mode can not use the max speed from ios->clock > for example UHS_SDR104_MAX_DTR 208000000 can not be used, only half may > be reached, at least currently. I don't fully understand the explanation, but if some of the other people with interest in dw-mmc (I've added some more to Cc now) think this makes sense, I'm fine with it too. > How about this desc > > * clock-freq-table: should be the frequency (in Hz) array of the ciu > clock > in each supported timing. > > 1. CIU clock rate in HZ for MMC_TIMING_LEGACY mode > > 2. CIU clock rate in HZ for MMC_TIMING_MMC_HS mode > 3. CIU clock rate in HZ for MMC_TIMING_SD_HS mode > 4. CIU clock rate in HZ for MMC_TIMING_UHS_SDR12 mode > > 5. CIU clock rate in HZ for MMC_TIMING_UHS_SDR25 mode > > 6. CIU clock rate in HZ for MMC_TIMING_UHS_SDR50 mode > > 7. CIU clock rate in HZ for MMC_TIMING_UHS_SDR104 mode > > 8. CIU clock rate in HZ for MMC_TIMING_SD_HS mode > > 9. CIU clock rate in HZ for MMC_TIMING_MMC_HS200 mode > Yes, that is much better. but please avoid using Linux internal identifiers (e.g. MMC_TIMING_LEGACY) and instead use the terminology from the MMC and SD specs. Also 'Hz' is the official symbol for Hertz, not 'HZ'. Arnd
On 12/13/2013 04:40 AM, Arnd Bergmann wrote: > On Thursday 12 December 2013, zhangfei wrote: >> On 12/12/2013 04:12 AM, Arnd Bergmann wrote: >>> On Wednesday 11 December 2013, zhangfei wrote: >>> >>> But aren't the times fixed for each mode? Why do you need to specify them in >>> the DT? I would expect that the clock rates for each mode are set in the >>> MMC and SD specifications. When you call clk_set_rate(), it should normally >>> be enough to ask for the clock you actually want and let the clk subsystem >>> figure out how to set up the parents and multipliers on the way. >> >> Yes. that's will be perfect. >> >> However, currently this ip still has no such capability. >> Input rate for init are diferent for different controller, not the >> init 400K, some are 13M, others are 25M, since different clock source. >> This can be easily solved by clock-freq-init = <25000000> >> 2. There is maxmum limit, also can be easily solved by define CLK_MAX. >> 3. However some mode can not use the max speed from ios->clock >> for example UHS_SDR104_MAX_DTR 208000000 can not be used, only half may >> be reached, at least currently. > > I don't fully understand the explanation, This is the ip's limitation currently, that some mode can only operate at limited freq, rather than the max freq from spec. Will upgrade to use ios->clock once the limitation is solved. but if some of the other > people with interest in dw-mmc (I've added some more to Cc now) think > this makes sense, I'm fine with it too. > Could I treat this as Ack or Partially Ack for the next version :) >> How about this desc >> >> * clock-freq-table: should be the frequency (in Hz) array of the ciu >> clock >> in each supported timing. >> >> 1. CIU clock rate in HZ for MMC_TIMING_LEGACY mode >> >> 2. CIU clock rate in HZ for MMC_TIMING_MMC_HS mode >> 3. CIU clock rate in HZ for MMC_TIMING_SD_HS mode >> 4. CIU clock rate in HZ for MMC_TIMING_UHS_SDR12 mode >> >> 5. CIU clock rate in HZ for MMC_TIMING_UHS_SDR25 mode >> >> 6. CIU clock rate in HZ for MMC_TIMING_UHS_SDR50 mode >> >> 7. CIU clock rate in HZ for MMC_TIMING_UHS_SDR104 mode >> >> 8. CIU clock rate in HZ for MMC_TIMING_SD_HS mode >> >> 9. CIU clock rate in HZ for MMC_TIMING_MMC_HS200 mode >> > > Yes, that is much better. but please avoid using Linux internal > identifiers (e.g. MMC_TIMING_LEGACY) and instead use the terminology from > the MMC and SD specs. Also 'Hz' is the official symbol for Hertz, not 'HZ'. > Update to * clock-freq-table: should be the frequency (in Hz) array of the ciu clock in each supported mode. 0. CIU clock rate in Hz for DS mode 1. CIU clock rate in Hz for MMC HS mode 2. CIU clock rate in Hz for SD HS mode 3. CIU clock rate in Hz for SDR12 mode 4. CIU clock rate in Hz for SDR25 mode 5. CIU clock rate in Hz for SDR50 mode 6. CIU clock rate in Hz for SDR104 mode 7. CIU clock rate in Hz for DDR50 mode 8. CIU clock rate in Hz for HS200 mode Thanks
diff --git a/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt new file mode 100644 index 000000000000..d816b89c386a --- /dev/null +++ b/Documentation/devicetree/bindings/mmc/k3-dw-mshc.txt @@ -0,0 +1,51 @@ +* Hisilicon specific extensions to the Synopsys Designware Mobile + Storage Host Controller + +Read synopsys-dw-mshc.txt for more details + +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 Hisilicon specific +extensions to the Synopsys Designware Mobile Storage Host Controller. + +Required Properties: + +* compatible: should be one of the following. + - "hisilicon,hi4511-dw-mshc": for controllers with hi4511 specific extentions. +* clk-table-num: should be number of clks in clk-table required by each mmc timing +* clk-table: should clock list required by each mmc timing + +Example: + + /* for Hi3620 */ + + /* SoC portion */ + dwmmc_0: dwmmc0@fcd03000 { + compatible = "hisilicon,hi4511-dw-mshc"; + reg = <0xfcd03000 0x1000>; + interrupts = <0 16 4>; + #address-cells = <1>; + #size-cells = <0>; + clocks = <&mmc_clock HI3620_SD_CIUCLK>, <&clock HI3620_DDRC_PER_CLK>; + clock-names = "ciu", "biu"; + clk-table-num = <8>; + clk-table = + <13000000 50000000 0 0 13000000 50000000 0 100000000>; + }; + + /* Board portion */ + dwmmc0@fcd03000 { + num-slots = <1>; + vmmc-supply = <&ldo12>; + fifo-depth = <0x100>; + supports-highspeed; + pinctrl-names = "default"; + pinctrl-0 = <&sd_pmx_pins &sd_cfg_func1 &sd_cfg_func2>; + slot@0 { + reg = <0>; + bus-width = <4>; + disable-wp; + cd-gpios = <&gpio10 3 0>; + }; + }; diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig index 7fc5099e44b2..45aaa2de0f58 100644 --- a/drivers/mmc/host/Kconfig +++ b/drivers/mmc/host/Kconfig @@ -575,6 +575,16 @@ config MMC_DW_SOCFPGA This selects support for Altera SoCFPGA specific extensions to the Synopsys DesignWare Memory Card Interface driver. +config MMC_DW_K3 + tristate "K3 specific extensions for Synopsys DW Memory Card Interface" + depends on MMC_DW + select MMC_DW_PLTFM + select MMC_DW_IDMAC + help + This selects support for Hisilicon K3 SoC specific extensions to the + Synopsys DesignWare Memory Card Interface driver. Select this option + for platforms based on Hisilicon K3 SoC's. + config MMC_DW_PCI tristate "Synopsys Designware MCI support on PCI bus" depends on MMC_DW && PCI diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile index c41d0c364509..64f5f8d35839 100644 --- a/drivers/mmc/host/Makefile +++ b/drivers/mmc/host/Makefile @@ -43,6 +43,7 @@ obj-$(CONFIG_MMC_DW) += dw_mmc.o obj-$(CONFIG_MMC_DW_PLTFM) += dw_mmc-pltfm.o obj-$(CONFIG_MMC_DW_EXYNOS) += dw_mmc-exynos.o obj-$(CONFIG_MMC_DW_SOCFPGA) += dw_mmc-socfpga.o +obj-$(CONFIG_MMC_DW_K3) += dw_mmc-k3.o obj-$(CONFIG_MMC_DW_PCI) += dw_mmc-pci.o obj-$(CONFIG_MMC_SH_MMCIF) += sh_mmcif.o obj-$(CONFIG_MMC_JZ4740) += jz4740_mmc.o diff --git a/drivers/mmc/host/dw_mmc-k3.c b/drivers/mmc/host/dw_mmc-k3.c new file mode 100644 index 000000000000..08fd7d7bbb23 --- /dev/null +++ b/drivers/mmc/host/dw_mmc-k3.c @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2013 Linaro Ltd. + * Copyright (c) 2013 Hisilicon Limited. + * + * 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/module.h> +#include <linux/platform_device.h> +#include <linux/clk.h> +#include <linux/mmc/host.h> +#include <linux/mmc/dw_mmc.h> +#include <linux/of_address.h> + +#include "dw_mmc.h" +#include "dw_mmc-pltfm.h" + +#define MAX_NUMS 10 +struct dw_mci_k3_priv_data { + u32 clk_table[MAX_NUMS]; +}; + +static void dw_mci_k3_set_ios(struct dw_mci *host, struct mmc_ios *ios) +{ + struct dw_mci_k3_priv_data *priv = host->priv; + + clk_set_rate(host->ciu_clk, priv->clk_table[ios->timing]); +} + +static int dw_mci_k3_parse_dt(struct dw_mci *host) +{ + struct dw_mci_k3_priv_data *priv; + int ret = 0, num = 0; + + priv = devm_kzalloc(host->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) { + dev_err(host->dev, "mem alloc failed for private data\n"); + return -ENOMEM; + } + host->priv = priv; + + ret = of_property_read_u32(host->dev->of_node, "clk-table-num", &num); + if (ret < 0) { + dev_err(host->dev, "not found clk-table-num\n"); + return ret; + } + if (num > MAX_NUMS) { + dev_err(host->dev, "clk-table-num too big\n"); + return -EINVAL; + } + + ret = of_property_read_u32_array(host->dev->of_node, "clk-table", + priv->clk_table, num); + if (ret) { + dev_err(host->dev, "not found clk-table\n"); + return ret; + } + + return 0; +} + +static unsigned long k3_dwmmc_caps[4] = { + MMC_CAP_4_BIT_DATA | MMC_CAP_SD_HIGHSPEED, + MMC_CAP_8_BIT_DATA | MMC_CAP_MMC_HIGHSPEED, + 0, + 0, +}; + +static const struct dw_mci_drv_data k3_drv_data = { + .caps = k3_dwmmc_caps, + .set_ios = dw_mci_k3_set_ios, + .parse_dt = dw_mci_k3_parse_dt, +}; + +static const struct of_device_id dw_mci_k3_match[] = { + { .compatible = "hisilicon,hi4511-dw-mshc", + .data = &k3_drv_data, }, + {}, +}; +MODULE_DEVICE_TABLE(of, dw_mci_k3_match); + +static int dw_mci_k3_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_k3_match, pdev->dev.of_node); + drv_data = match->data; + + return dw_mci_pltfm_register(pdev, drv_data); +} + +static int dw_mci_k3_suspend(struct device *dev) +{ + struct dw_mci *host = dev_get_drvdata(dev); + + if (!IS_ERR(host->ciu_clk)) + clk_disable_unprepare(host->ciu_clk); + + return dw_mci_suspend(host); +} + +static int dw_mci_k3_resume(struct device *dev) +{ + struct dw_mci *host = dev_get_drvdata(dev); + int ret = 0; + + ret = clk_prepare_enable(host->ciu_clk); + if (ret) { + dev_err(host->dev, "failed to enable ciu clock\n"); + return ret; + } + + return dw_mci_resume(host); +} + +SIMPLE_DEV_PM_OPS(dw_mci_k3_pmops, dw_mci_k3_suspend, dw_mci_k3_resume); + +static struct platform_driver dw_mci_k3_pltfm_driver = { + .probe = dw_mci_k3_probe, + .remove = dw_mci_pltfm_remove, + .driver = { + .name = "dwmmc_k3", + .of_match_table = dw_mci_k3_match, + .pm = &dw_mci_k3_pmops, + }, +}; + +module_platform_driver(dw_mci_k3_pltfm_driver); + +MODULE_DESCRIPTION("K3 Specific DW-MSHC Driver Extension"); +MODULE_LICENSE("GPL v2"); +MODULE_ALIAS("platform:dwmmc-k3");