From patchwork Tue Apr 21 08:31:28 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Kuninori Morimoto X-Patchwork-Id: 6246221 X-Patchwork-Delegate: geert@linux-m68k.org Return-Path: X-Original-To: patchwork-linux-sh@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id A074F9F32B for ; Tue, 21 Apr 2015 08:31:38 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A09762017E for ; Tue, 21 Apr 2015 08:31:37 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id 7D92820416 for ; Tue, 21 Apr 2015 08:31:36 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752263AbbDUIbe (ORCPT ); Tue, 21 Apr 2015 04:31:34 -0400 Received: from relmlor3.renesas.com ([210.160.252.173]:64417 "EHLO relmlie2.idc.renesas.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S1750987AbbDUIbc (ORCPT ); Tue, 21 Apr 2015 04:31:32 -0400 Received: from unknown (HELO relmlir2.idc.renesas.com) ([10.200.68.152]) by relmlie2.idc.renesas.com with ESMTP; 21 Apr 2015 17:31:31 +0900 Received: from relmlac2.idc.renesas.com (relmlac2.idc.renesas.com [10.200.69.22]) by relmlir2.idc.renesas.com (Postfix) with ESMTP id 7201E5395F; Tue, 21 Apr 2015 17:31:31 +0900 (JST) Received: by relmlac2.idc.renesas.com (Postfix, from userid 0) id 649102806E; Tue, 21 Apr 2015 17:31:31 +0900 (JST) Received: from relmlac2.idc.renesas.com (localhost [127.0.0.1]) by relmlac2.idc.renesas.com (Postfix) with ESMTP id 5F8422806D; Tue, 21 Apr 2015 17:31:31 +0900 (JST) Received: from relmlii1.idc.renesas.com [10.200.68.65] by relmlac2.idc.renesas.com with ESMTP id TAF22362; Tue, 21 Apr 2015 17:31:31 +0900 X-IronPort-AV: E=Sophos;i="5.11,614,1422889200"; d="scan'208";a="184513474" Received: from mail-sg1lp0092.outbound.protection.outlook.com (HELO APAC01-SG1-obe.outbound.protection.outlook.com) ([207.46.51.92]) by relmlii1.idc.renesas.com with ESMTP/TLS/AES256-SHA; 21 Apr 2015 17:31:30 +0900 Authentication-Results: linaro.org; dkim=none (message not signed) header.d=none; Received: from morimoto-PC.renesas.com (211.11.155.132) by SINPR06MB316.apcprd06.prod.outlook.com (10.141.115.155) with Microsoft SMTP Server (TLS) id 15.1.136.25; Tue, 21 Apr 2015 08:31:28 +0000 Message-ID: <87r3rdubmv.wl%kuninori.morimoto.gx@renesas.com> From: Kuninori Morimoto Subject: [PATCH 3/3 v3] mmc: sh_mmcif: calculate best clock with parent clock User-Agent: Wanderlust/2.15.9 Emacs/24.3 Mule/6.0 To: Ulf Hansson CC: linux-mmc , Simon , Magnus , Linux-SH , Laurent , kobayashi In-Reply-To: <87vbgpubvr.wl%kuninori.morimoto.gx@renesas.com> References: <873840a4ch.wl%kuninori.morimoto.gx@renesas.com> <87vbgpubvr.wl%kuninori.morimoto.gx@renesas.com> MIME-Version: 1.0 (generated by SEMI-EPG 1.14.7 - "Harue") Date: Tue, 21 Apr 2015 08:31:28 +0000 X-Originating-IP: [211.11.155.132] X-ClientProxiedBy: OS2PR01CA0011.jpnprd01.prod.outlook.com (25.161.74.149) To SINPR06MB316.apcprd06.prod.outlook.com (10.141.115.155) X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:SINPR06MB316; X-Forefront-Antispam-Report: BMV:1; SFV:NSPM; SFS:(10019020)(6009001)(77096005)(47776003)(53416004)(36756003)(66066001)(19580405001)(2950100001)(229853001)(92566002)(50466002)(33646002)(23726002)(19580395003)(122386002)(46102003)(40100003)(83506001)(42186005)(4001350100001)(76176999)(54356999)(77156002)(62966003)(50986999)(86362001)(46406003)(87976001)(110136001)(4001430100001); DIR:OUT; SFP:1102; SCL:1; SRVR:SINPR06MB316; H:morimoto-PC.renesas.com; FPR:; SPF:None; MLV:sfv; LANG:en; X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:; X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(601004)(5002010)(5005006); SRVR:SINPR06MB316; BCL:0; PCL:0; RULEID:; SRVR:SINPR06MB316; X-Forefront-PRVS: 0553CBB77A X-OriginatorOrg: renesas.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 21 Apr 2015 08:31:28.6453 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: SINPR06MB316 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=unavailable 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 setup parent clock. This patch adds parent clock setup method, and r8a7790/r8a7791 can use it. renesas,mmcif already contain renesas,mmcif-r8a7790/r8a7791 on compatible string. So there is no update for binding Document. Signed-off-by: Kuninori Morimoto Tested-by: Keita Kobayashi --- v1 -> v2 - tidyup log explain. (use "parent clock" instead of "PLL") v2 -> v3 - add SH-ML drivers/mmc/host/sh_mmcif.c | 79 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 76 insertions(+), 3 deletions(-) diff --git a/drivers/mmc/host/sh_mmcif.c b/drivers/mmc/host/sh_mmcif.c index 5282c5b..6ae836b 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,12 @@ enum mmcif_wait_for { MMCIF_WAIT_FOR_STOP, }; +struct sh_mmcif_parent_clk { + unsigned int max; /* if exist: R-Car has MMC CKCR on CPG */ + unsigned int min; /* if exist: R-Car has MMC CKCR on CPG */ + u32 clkdiv_map; /* see CE_CLK_CTRL::CLKDIV */ +}; + struct sh_mmcif_host { struct mmc_host *mmc; struct mmc_request *mrq; @@ -249,6 +256,7 @@ struct sh_mmcif_host { bool ccs_enable; /* Command Completion Signal support */ bool clk_ctrl2_enable; struct mutex thread_lock; + const struct sh_mmcif_parent_clk *parent_clk; /* DMA support */ struct dma_chan *chan_rx; @@ -257,8 +265,16 @@ struct sh_mmcif_host { bool dma_active; }; +static const struct sh_mmcif_parent_clk mmcif_gen2_parent_clk = { + .max = 97500000, + .min = 12187500, + .clkdiv_map = 0x3ff, +}; + static const struct of_device_id mmcif_of_match[] = { { .compatible = "renesas,sh-mmcif" }, + { .compatible = "renesas,mmcif-r8a7790", .data = &mmcif_gen2_parent_clk}, + { .compatible = "renesas,mmcif-r8a7791", .data = &mmcif_gen2_parent_clk}, { } }; MODULE_DEVICE_TABLE(of, mmcif_of_match); @@ -490,12 +506,51 @@ static void sh_mmcif_clock_control(struct sh_mmcif_host *host, unsigned int clk) if (!clk) return; - if (sup_pclk && clk == host->clk) + + if (host->parent_clk) { + const struct sh_mmcif_parent_clk *pclk = host->parent_clk; + unsigned int parent_freq, clkdiv, myclk, diff_min, diff; + int i, j; + + /* FIXME */ + if (pclk->max != pclk->min * (pclk->max / pclk->min)) { + dev_err(&host->pd->dev, "not assumed parent clk\n"); + return; + } + + parent_freq = 0; + clkdiv = 0; + diff_min = ~0; + for (i = pclk->max / pclk->min; i > 0; i--) { + for (j = fls(pclk->clkdiv_map); j >= 0; j--) { + if (!((1 << j) & pclk->clkdiv_map)) + continue; + + myclk = ((pclk->min * i) / (1 << (j + 1))); + diff = (myclk > clk) ? myclk - clk : clk - myclk; + + if (diff <= diff_min) { + parent_freq = pclk->min * i; + clkdiv = j; + diff_min = diff; + } + } + } + + dev_dbg(&host->pd->dev, "clk %d/%d (%d, %x)\n", + (parent_freq / (1 << (clkdiv + 1))), clk, + parent_freq, clkdiv); + + clk_set_rate(host->hclk, parent_freq); + sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, + CLK_CLEAR & (clkdiv << 16)); + } else if (sup_pclk && clk == host->clk) { sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_SUP_PCLK); - else + } else { sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_CLEAR & ((fls(DIV_ROUND_UP(host->clk, clk) - 1) - 1) << 16)); + } sh_mmcif_bitset(host, MMCIF_CE_CLK_CTRL, CLK_ENABLE); } @@ -982,10 +1037,23 @@ static int sh_mmcif_clk_update(struct sh_mmcif_host *host) { int ret = clk_prepare_enable(host->hclk); - if (!ret) { + if (ret) + return ret; + + if (!host->parent_clk) { host->clk = clk_get_rate(host->hclk); host->mmc->f_max = host->clk / 2; host->mmc->f_min = host->clk / 512; + } else { + const struct sh_mmcif_parent_clk *pclk = host->parent_clk; + + host->clk = clk_get_rate(host->hclk); + host->mmc->f_max = pclk->max / (1 << ffs(pclk->clkdiv_map)); + host->mmc->f_min = pclk->min / (1 << fls(pclk->clkdiv_map)); + + dev_dbg(&host->pd->dev, "parent clk %d/%d, %d/%d\n", + pclk->max, pclk->min, + host->mmc->f_max, host->mmc->f_min); } return ret; @@ -1389,6 +1457,7 @@ static int sh_mmcif_probe(struct platform_device *pdev) struct device *dev = &pdev->dev; struct sh_mmcif_plat_data *pd = dev->platform_data; struct resource *res; + const struct of_device_id *of_id = of_match_device(mmcif_of_match, dev); void __iomem *reg; const char *name; @@ -1421,6 +1490,10 @@ static int sh_mmcif_probe(struct platform_device *pdev) host->pd = pdev; + host->parent_clk = NULL; + if (of_id) + host->parent_clk = of_id->data; + spin_lock_init(&host->lock); mmc->ops = &sh_mmcif_ops;