From patchwork Thu May 14 07:22:46 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuninori Morimoto X-Patchwork-Id: 6403021 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork2.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork2.web.kernel.org (Postfix) with ESMTP id 47FC3BEEE1 for ; Thu, 14 May 2015 07:22:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 325D4203F4 for ; Thu, 14 May 2015 07:22:58 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id E548B203B0 for ; Thu, 14 May 2015 07:22:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751746AbbENHWz (ORCPT ); Thu, 14 May 2015 03:22:55 -0400 Received: from relmlor3.renesas.com ([210.160.252.173]:47313 "EHLO relmlie2.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750759AbbENHWv (ORCPT ); Thu, 14 May 2015 03:22:51 -0400 Received: from unknown (HELO relmlir4.idc.renesas.com) ([10.200.68.154]) by relmlie2.idc.renesas.com with ESMTP; 14 May 2015 16:22:49 +0900 Received: from relmlac2.idc.renesas.com (relmlac2.idc.renesas.com [10.200.69.22]) by relmlir4.idc.renesas.com (Postfix) with ESMTP id 2EF5F405FE; Thu, 14 May 2015 16:22:49 +0900 (JST) Received: by relmlac2.idc.renesas.com (Postfix, from userid 0) id 276AB2806E; Thu, 14 May 2015 16:22:49 +0900 (JST) Received: from relmlac2.idc.renesas.com (localhost [127.0.0.1]) by relmlac2.idc.renesas.com (Postfix) with ESMTP id 2065C2806D; Thu, 14 May 2015 16:22:49 +0900 (JST) Received: from relmlii1.idc.renesas.com [10.200.68.65] by relmlac2.idc.renesas.com with ESMTP id SAS05663; Thu, 14 May 2015 16:22:49 +0900 X-IronPort-AV: E=Sophos;i="5.13,426,1427727600"; d="scan'208";a="186177802" Received: from mail-hk1lp0120.outbound.protection.outlook.com (HELO APAC01-HK1-obe.outbound.protection.outlook.com) ([207.46.51.120]) by relmlii1.idc.renesas.com with ESMTP/TLS/AES256-SHA; 14 May 2015 16:22:48 +0900 Authentication-Results: linaro.org; dkim=none (message not signed) header.d=none; Received: from morimoto-PC.renesas.com (211.11.155.132) by HKNPR06MB305.apcprd06.prod.outlook.com (10.141.37.16) with Microsoft SMTP Server (TLS) id 15.1.160.19; Thu, 14 May 2015 07:22:46 +0000 Message-ID: <871tijpqu8.wl%kuninori.morimoto.gx@renesas.com> From: Kuninori Morimoto Subject: [PATCH 3/5 v6] mmc: sh_mmcif: calculate best clock with parent clock User-Agent: Wanderlust/2.15.9 Emacs/24.3 Mule/6.0 MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") To: Ulf Hansson CC: linux-mmc , Simon , Magnus , Linux-SH , Laurent , Geert Uytterhoeven , kobayashi In-Reply-To: <87617vpqy3.wl%kuninori.morimoto.gx@renesas.com> References: <873840a4ch.wl%kuninori.morimoto.gx@renesas.com> <87617vpqy3.wl%kuninori.morimoto.gx@renesas.com> Date: Thu, 14 May 2015 07:22:46 +0000 X-Originating-IP: [211.11.155.132] X-ClientProxiedBy: KAWPR01CA0021.jpnprd01.prod.outlook.com (25.161.24.31) To HKNPR06MB305.apcprd06.prod.outlook.com (10.141.37.16) X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:HKNPR06MB305; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(5005006)(3002001); SRVR:HKNPR06MB305; BCL:0; PCL:0; RULEID:; SRVR:HKNPR06MB305; X-Forefront-PRVS: 0576145E86 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10019020)(6009001)(50466002)(36756003)(87976001)(40100003)(122386002)(229853001)(33646002)(86362001)(46406003)(54356999)(76176999)(50986999)(47776003)(4001350100001)(66066001)(83506001)(62966003)(77156002)(19580405001)(19580395003)(5001960100002)(107886002)(23726002)(92566002)(53416004)(42186005)(77096005)(189998001)(2950100001)(46102003)(110136002)(4001430100001); DIR:OUT; SFP:1102; SCL:1; SRVR:HKNPR06MB305; H:morimoto-PC.renesas.com; FPR:; SPF:None; MLV:sfv; LANG:en; X-OriginatorOrg: renesas.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 14 May 2015 07:22:46.0910 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: HKNPR06MB305 Sender: linux-sh-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-sh@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=ham version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP From: Kuninori Morimoto 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 Tested-by: Keita Kobayashi --- v5 -> v6 - it uses max-frequency - don't add new compatible string .../devicetree/bindings/mmc/renesas,mmcif.txt | 3 + drivers/mmc/host/sh_mmcif.c | 84 +++++++++++++++++++--- 2 files changed, 78 insertions(+), 9 deletions(-) diff --git a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt index 299081f..d38942f 100644 --- a/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt +++ b/Documentation/devicetree/bindings/mmc/renesas,mmcif.txt @@ -18,6 +18,8 @@ Required properties: dma-names property. - dma-names: must contain "tx" for the transmit DMA channel and "rx" for the receive DMA channel. +- max-frequency: Maximum operating clock frequency, driver uses default clock + frequency if it is not set. Example: R8A7790 (R-Car H2) MMCIF0 @@ -29,4 +31,5 @@ Example: R8A7790 (R-Car H2) MMCIF0 clocks = <&mstp3_clks R8A7790_CLK_MMCIF0>; dmas = <&dmac0 0xd1>, <&dmac0 0xd2>; dma-names = "tx", "rx"; + max-frequency = <97500000>; }; diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index e13c5f41..554fa9d 100644 --- a/drivers/mmc/host/sh_mmcif.c +++ b/drivers/mmc/host/sh_mmcif.c @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -224,6 +225,9 @@ enum sh_mmcif_wait_for { MMCIF_WAIT_FOR_STOP, }; +/* + * difference for each SoC + */ struct sh_mmcif_host { struct mmc_host *mmc; struct mmc_request *mrq; @@ -248,6 +252,7 @@ struct sh_mmcif_host { bool ccs_enable; /* Command Completion Signal support */ bool clk_ctrl2_enable; struct mutex thread_lock; + u32 clkdiv_map; /* see CE_CLK_CTRL::CLKDIV */ /* DMA support */ struct dma_chan *chan_rx; @@ -492,19 +497,55 @@ static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) struct sh_mmcif_plat_data *p = dev->platform_data; bool sup_pclk = p ? p->sup_pclk : false; unsigned int current_clk = clk_get_rate(host->clk); + unsigned int clkdiv; sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); sh_mmcif_bitclr(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR); if (!clk) return; - if (sup_pclk && clk == current_clk) - sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); - else - sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & - ((fls(DIV_ROUND_UP(current_clk, - clk) - 1) - 1) << 16)); + if (host->clkdiv_map) { + unsigned int freq, best_freq, myclk, div, diff_min, diff; + int i; + + clkdiv = 0; + diff_min = ~0; + best_freq = 0; + for (i = 31; i >= 0; i--) { + if (!((1 << i) & host->clkdiv_map)) + continue; + + /* + * clk = parent_freq / div + * -> parent_freq = clk x div + */ + + div = 1 << (i + 1); + freq = clk_round_rate(host->clk, clk * div); + myclk = freq / div; + diff = (myclk > clk) ? myclk - clk : clk - myclk; + + if (diff <= diff_min) { + best_freq = freq; + clkdiv = i; + diff_min = diff; + } + } + + dev_dbg(dev, "clk %u/%u (%u, 0x%x)\n", + (best_freq / (1 << (clkdiv + 1))), clk, + best_freq, clkdiv); + + clk_set_rate(host->clk, best_freq); + clkdiv = clkdiv << 16; + } else if (sup_pclk && clk == current_clk) { + clkdiv = CLK_SUP_PCLK; + } else { + clkdiv = (fls(DIV_ROUND_UP(current_clk, clk) - 1) - 1) << 16; + } + + sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & clkdiv); sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); } @@ -1000,10 +1041,35 @@ static void sh_mmcif_request(struct mmc_host *mmc, struct mmc_request *mrq) static void sh_mmcif_clk_setup(struct sh_mmcif_host *host) { - unsigned int clk = clk_get_rate(host->clk); + struct device *dev = sh_mmcif_host_to_dev(host); + + if (host->mmc->f_max) { + unsigned int f_max, f_min, f_min_old; + + f_max = host->mmc->f_max; + for (f_min_old = f_max; f_min_old > 2;) { + f_min = clk_round_rate(host->clk, f_min_old / 2); + if (f_min == f_min_old) + break; + f_min_old = f_min; + } + + /* + * This driver assumes this SoC is R-Car Gen2 or later + */ + host->clkdiv_map = 0x3ff; + + host->mmc->f_max = f_max / (1 << ffs(host->clkdiv_map)); + host->mmc->f_min = f_min / (1 << fls(host->clkdiv_map)); + } else { + unsigned int clk = clk_get_rate(host->clk); + + host->mmc->f_max = clk / 2; + host->mmc->f_min = clk / 512; + } - host->mmc->f_max = clk / 2; - host->mmc->f_min = clk / 512; + dev_dbg(dev, "clk max/min = %d/%d\n", + host->mmc->f_max, host->mmc->f_min); } static void sh_mmcif_set_power(struct sh_mmcif_host *host, struct mmc_ios *ios)