Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mmc: sh_mmcif: calculate best clock with parent clock

MMCIF IP on R-Car series has parent clock which can be set several rate,
and it was not implemented on old SH-Mobile series (= SH-Mobile series
parent clock was fixed rate) R-Car series MMCIF can use more high speed
access if it setups parent clock. This patch adds parent clock setup
method. It will be used if DT has "max-frequency", and then, this driver
assumes it is booted on R-Car Gen2 or later SoC. Because SH-Mobile series
(which doesn't boot from DT) and R-Car series (which boots from DT) have
different divider.

Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Tested-by: Keita Kobayashi <keita.kobayashi.ym@renesas.com>
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
[Ulf: Silence compiler warning]

authored by

Kuninori Morimoto and committed by
Ulf Hansson
89d49a70 1b1a694d

+78 -9
+3
Documentation/devicetree/bindings/mmc/renesas,mmcif.txt
··· 18 18 dma-names property. 19 19 - dma-names: must contain "tx" for the transmit DMA channel and "rx" for the 20 20 receive DMA channel. 21 + - max-frequency: Maximum operating clock frequency, driver uses default clock 22 + frequency if it is not set. 21 23 22 24 23 25 Example: R8A7790 (R-Car H2) MMCIF0 ··· 31 29 clocks = <&mstp3_clks R8A7790_CLK_MMCIF0>; 32 30 dmas = <&dmac0 0xd1>, <&dmac0 0xd2>; 33 31 dma-names = "tx", "rx"; 32 + max-frequency = <97500000>; 34 33 };
+75 -9
drivers/mmc/host/sh_mmcif.c
··· 57 57 #include <linux/mmc/slot-gpio.h> 58 58 #include <linux/mod_devicetable.h> 59 59 #include <linux/mutex.h> 60 + #include <linux/of_device.h> 60 61 #include <linux/pagemap.h> 61 62 #include <linux/platform_device.h> 62 63 #include <linux/pm_qos.h> ··· 225 224 MMCIF_WAIT_FOR_STOP, 226 225 }; 227 226 227 + /* 228 + * difference for each SoC 229 + */ 228 230 struct sh_mmcif_host { 229 231 struct mmc_host *mmc; 230 232 struct mmc_request *mrq; ··· 252 248 bool ccs_enable; /* Command Completion Signal support */ 253 249 bool clk_ctrl2_enable; 254 250 struct mutex thread_lock; 251 + u32 clkdiv_map; /* see CE_CLK_CTRL::CLKDIV */ 255 252 256 253 /* DMA support */ 257 254 struct dma_chan *chan_rx; ··· 497 492 struct sh_mmcif_plat_data *p = dev->platform_data; 498 493 bool sup_pclk = p ? p->sup_pclk : false; 499 494 unsigned int current_clk = clk_get_rate(host->clk); 495 + unsigned int clkdiv; 500 496 501 497 sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); 502 498 sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR); 503 499 504 500 if (!clk) 505 501 return; 506 - if (sup_pclk && clk == current_clk) 507 - sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); 508 - else 509 - sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & 510 - ((fls(DIV_ROUND_UP(current_clk, 511 - clk) - 1) - 1) << 16)); 512 502 503 + if (host->clkdiv_map) { 504 + unsigned int freq, best_freq, myclk, div, diff_min, diff; 505 + int i; 506 + 507 + clkdiv = 0; 508 + diff_min = ~0; 509 + best_freq = 0; 510 + for (i = 31; i >= 0; i--) { 511 + if (!((1 << i) & host->clkdiv_map)) 512 + continue; 513 + 514 + /* 515 + * clk = parent_freq / div 516 + * -> parent_freq = clk x div 517 + */ 518 + 519 + div = 1 << (i + 1); 520 + freq = clk_round_rate(host->clk, clk * div); 521 + myclk = freq / div; 522 + diff = (myclk > clk) ? myclk - clk : clk - myclk; 523 + 524 + if (diff <= diff_min) { 525 + best_freq = freq; 526 + clkdiv = i; 527 + diff_min = diff; 528 + } 529 + } 530 + 531 + dev_dbg(dev, "clk %u/%u (%u, 0x%x)\n", 532 + (best_freq / (1 << (clkdiv + 1))), clk, 533 + best_freq, clkdiv); 534 + 535 + clk_set_rate(host->clk, best_freq); 536 + clkdiv = clkdiv << 16; 537 + } else if (sup_pclk && clk == current_clk) { 538 + clkdiv = CLK_SUP_PCLK; 539 + } else { 540 + clkdiv = (fls(DIV_ROUND_UP(current_clk, clk) - 1) - 1) << 16; 541 + } 542 + 543 + sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & clkdiv); 513 544 sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); 514 545 } 515 546 ··· 1041 1000 1042 1001 static void sh_mmcif_clk_setup(struct sh_mmcif_host *host) 1043 1002 { 1044 - unsigned int clk = clk_get_rate(host->clk); 1003 + struct device *dev = sh_mmcif_host_to_dev(host); 1045 1004 1046 - host->mmc->f_max = clk / 2; 1047 - host->mmc->f_min = clk / 512; 1005 + if (host->mmc->f_max) { 1006 + unsigned int f_max, f_min = 0, f_min_old; 1007 + 1008 + f_max = host->mmc->f_max; 1009 + for (f_min_old = f_max; f_min_old > 2;) { 1010 + f_min = clk_round_rate(host->clk, f_min_old / 2); 1011 + if (f_min == f_min_old) 1012 + break; 1013 + f_min_old = f_min; 1014 + } 1015 + 1016 + /* 1017 + * This driver assumes this SoC is R-Car Gen2 or later 1018 + */ 1019 + host->clkdiv_map = 0x3ff; 1020 + 1021 + host->mmc->f_max = f_max / (1 << ffs(host->clkdiv_map)); 1022 + host->mmc->f_min = f_min / (1 << fls(host->clkdiv_map)); 1023 + } else { 1024 + unsigned int clk = clk_get_rate(host->clk); 1025 + 1026 + host->mmc->f_max = clk / 2; 1027 + host->mmc->f_min = clk / 512; 1028 + } 1029 + 1030 + dev_dbg(dev, "clk max/min = %d/%d\n", 1031 + host->mmc->f_max, host->mmc->f_min); 1048 1032 } 1049 1033 1050 1034 static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios)