From patchwork Fri Aug 4 17:43:50 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jerome Brunet X-Patchwork-Id: 9881835 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 0469C602B8 for ; Fri, 4 Aug 2017 17:46:33 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id E51B42891B for ; Fri, 4 Aug 2017 17:46:32 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id D9CFA28930; Fri, 4 Aug 2017 17:46:32 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 44AB02891B for ; Fri, 4 Aug 2017 17:46:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:References: In-Reply-To:Message-Id:Date:Subject:To:From:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Owner; bh=OMigr1GLDg6JgDQCgkOEUUNvk2U3+5x9EmDOEVT9HTY=; b=gltFXOnDMTNbiDn0C6DNhTp/Or NBJIa0/Y4qGp3+Mrja3mu6/aO77zhgFUdgOl7mR/2DvpMWMe13rfLwreBHq3zUuzKIq3kUXxd2rGm VcpZehkodgH1GsBOQqJpozJY25OBnYU8dNdrx2tRlGeCYlMmtAVbihgcHdWI0hx70CmLs0KXRJc7P Po5DCt57STuDbmT7NjOHL4myCcbxHmZX27je+wcjgFwe7CvGMD8X9yt702UcFK5GeUa4eA1oTYslW QBYCESqyezbD3mBnHat7uMok672DShL4Eavul7NdnIycQJN/VqagWAyCCDF46EAiqFIOApqsPqGIY X6aYUeGQ==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1ddgg4-0000gN-RB; Fri, 04 Aug 2017 17:46:24 +0000 Received: from casper.infradead.org ([2001:8b0:10b:1236::1]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1ddgeO-0006Yo-4r for linux-amlogic@bombadil.infradead.org; Fri, 04 Aug 2017 17:44:40 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=infradead.org; s=casper.20170209; h=References:In-Reply-To:Message-Id:Date: Subject:Cc:To:From:Sender:Reply-To:MIME-Version:Content-Type: Content-Transfer-Encoding:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:List-Id: List-Help:List-Unsubscribe:List-Subscribe:List-Post:List-Owner:List-Archive; bh=IPz9unC1TdOReDr7ZALuj52Zp1canmHZsl2jrYC2me8=; b=tgRwT83Q8vipNXPnwcLwZFJ5s WxR3mtrULAIpWk64zvOJasgqiC8Bf+gbSKjTNI9XRsrb13l4Uz9IUMveFV6sbM/nXS6iX1RXg5TXe HdaxW8lwf4v4FkFJGr07cIWLciJwTDYkJe4B52pOaycoxkwiXYIGQnU23uAuKx7wtYNIBDRGB0wVn GBjvUcgg5RlHDMM/sIrm3srvhY7xd8fOcR/hkGtcRUn6J1mwXvM6s7QEa/66zbLC/SawnuHMsVQpc VTGPa4PdRY3v09Q+dRMHjJEYjjNIlDChar3lQfDW2nLW/e44rek93hnHJqDf3/Jt9vugw6oloJvG3 e+d20/y2Q==; Received: from mail-wm0-x234.google.com ([2a00:1450:400c:c09::234]) by casper.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1ddgeI-0005gY-60 for linux-amlogic@lists.infradead.org; Fri, 04 Aug 2017 17:44:38 +0000 Received: by mail-wm0-x234.google.com with SMTP id t201so25293956wmt.1 for ; Fri, 04 Aug 2017 10:44:16 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=baylibre-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=IPz9unC1TdOReDr7ZALuj52Zp1canmHZsl2jrYC2me8=; b=QwFpWfCp5Tk+tUcDs7NUVUb8gvKTZKkqZGhmIbjV6fPo2jojqrz2wV5jOgOT/S5JQP nMgAgyqx8rz1uMYXW1c3xoX1+bGJP6WbLXI001/EwD+RTjw3Zb4CRZ+39WJipAgmuLY1 gWKjT2mZQeDOU7UYSQsP1iqr7mGEQXS8W+R2M7jcUjCiEK4CH0HoGQhKAwS6zVBJFKn6 4ZZxbNwyQZJ3F6ZumdBYYwFDdg0G7f5FcZN8h02GES/TaDbb/lpGE8bNBsJ7+3fPL6eG G4MZhM6NBOHuY8jZzJBWAhRrjTU8wU8wYrYjCduXkYafRXNUGdGpz3JlLa9X304o09us iUPw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=IPz9unC1TdOReDr7ZALuj52Zp1canmHZsl2jrYC2me8=; b=RMI4wBOKaKcYXY8hSIXpJ/J+75uG/ZGdL9LamnyBRuqwxyxj9jyOMWB5tTqMQZZ5PJ iG8lep+39KkOLWaON8cXNTtm4eGdvCXbrG1kNvwyJrQHenfeO7CSO6KWf/TcxCs+Zmjo vFoPWpznWeQ8qCAdbB+JdrYTw1oEscxV3u8KHJMbMZhCYC3L/9SGSa4d2LlZ7qUYTJAT BY/v1Xyx+illRa37qT4pZK0cmtpuFckUDwHSmj6ehvDblobCoHIvnq7+LUzGQkX9lp8g 0ifgQIoJ1q5aZgpxtic/DO+hjg3f61ZEnHIChiXF4Q+k8FQBYxoPXSCVFMF7LyRnukVm hmjg== X-Gm-Message-State: AHYfb5hBGkDalnaR3uU4vNA/jLtH+84N0pdD6y4VIMdMpRJlxlXyHcL+ gDar72NBWz0PPrtR X-Received: by 10.28.150.87 with SMTP id y84mr1750679wmd.67.1501868655320; Fri, 04 Aug 2017 10:44:15 -0700 (PDT) Received: from localhost.localdomain (cag06-3-82-243-161-21.fbx.proxad.net. [82.243.161.21]) by smtp.googlemail.com with ESMTPSA id p17sm996082wma.45.2017.08.04.10.44.14 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 04 Aug 2017 10:44:14 -0700 (PDT) From: Jerome Brunet To: Ulf Hansson , Kevin Hilman , Carlo Caione Subject: [PATCH 11/14] mmc: meson-gx: rework tuning function Date: Fri, 4 Aug 2017 19:43:50 +0200 Message-Id: <20170804174353.16486-12-jbrunet@baylibre.com> X-Mailer: git-send-email 2.9.4 In-Reply-To: <20170804174353.16486-1-jbrunet@baylibre.com> References: <20170804174353.16486-1-jbrunet@baylibre.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170804_184434_376896_62D67789 X-CRM114-Status: GOOD ( 26.89 ) X-BeenThere: linux-amlogic@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: linux-amlogic@lists.infradead.org, linux-mmc@vger.kernel.org, linux-kernel@vger.kernel.org, linux-arm-kernel@lists.infradead.org, Jerome Brunet MIME-Version: 1.0 Sender: "linux-amlogic" Errors-To: linux-amlogic-bounces+patchwork-linux-amlogic=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP Rework tuning function of the rx phase, with the addition of rx delay. This allow a more fine setting of the rx phase, which allows to use new modes such as SDR50. Also, use 270 degree Tx phase as it make eMMC DDR52 mode functional on the libretech-cc, without any regression so far. Signed-off-by: Jerome Brunet --- drivers/mmc/host/meson-gx-mmc.c | 215 ++++++++++++++++++++++++++++++---------- 1 file changed, 160 insertions(+), 55 deletions(-) diff --git a/drivers/mmc/host/meson-gx-mmc.c b/drivers/mmc/host/meson-gx-mmc.c index 33ab341a8b33..560de8faea50 100644 --- a/drivers/mmc/host/meson-gx-mmc.c +++ b/drivers/mmc/host/meson-gx-mmc.c @@ -50,6 +50,13 @@ #define CLK_PHASE_90 1 #define CLK_PHASE_180 2 #define CLK_PHASE_270 3 +#define CLK_PHASE_NUM 4 +#define CLK_TX_DELAY_MASK GENMASK(19, 16) +#define CLK_RX_DELAY_MASK GENMASK(23, 20) +#define CLK_DELAY_STEP_PS 200 +#define CLK_PHASE_STEP 30 +#define CLK_PHASE_POINT_NUM (360 / CLK_PHASE_STEP) +#define CLK_DELAY_MAX 0xf #define CLK_ALWAYS_ON BIT(24) #define SD_EMMC_DELAY 0x4 @@ -120,12 +127,6 @@ #define MUX_CLK_NUM_PARENTS 2 -struct meson_tuning_params { - u8 core_phase; - u8 tx_phase; - u8 rx_phase; -}; - struct sd_emmc_desc { u32 cmd_cfg; u32 cmd_arg; @@ -150,7 +151,6 @@ struct meson_host { struct sd_emmc_desc *descs; dma_addr_t descs_dma_addr; - struct meson_tuning_params tp; bool vqmmc_enabled; }; @@ -269,6 +269,35 @@ static void meson_mmc_post_req(struct mmc_host *mmc, struct mmc_request *mrq, mmc_get_dma_dir(data)); } +static void meson_mmc_clk_phase_dflt(struct meson_host *host) +{ + u32 val; + + val = readl(host->regs + SD_EMMC_CLOCK); + val &= ~(CLK_CORE_PHASE_MASK | CLK_TX_PHASE_MASK | CLK_RX_PHASE_MASK | + CLK_TX_DELAY_MASK | CLK_RX_DELAY_MASK); + + /* + * Set phases : These values are mostly the datasheet recommended ones + * except for the Tx phase. Datasheet recommends 180 but DDR52 mode + * does not work with that value. 270 works just fine, w/o any + * regression on the other modes so far. + * + * At this point, cylcing on the Tx phase in the tuning function does + * not seems necessary. We may add it later on, if some mode high speed + * mode needs different Tx phase. + */ + val |= FIELD_PREP(CLK_CORE_PHASE_MASK, CLK_PHASE_180); + val |= FIELD_PREP(CLK_TX_PHASE_MASK, CLK_PHASE_270); + val |= FIELD_PREP(CLK_RX_PHASE_MASK, CLK_PHASE_0); + + /* Reset delays */ + val |= FIELD_PREP(CLK_TX_DELAY_MASK, 0); + val |= FIELD_PREP(CLK_RX_DELAY_MASK, 0); + + writel(val, host->regs + SD_EMMC_CLOCK); +} + static int meson_mmc_clk_set(struct meson_host *host, unsigned long clk_rate) { struct mmc_host *mmc = host->mmc; @@ -348,9 +377,6 @@ static int meson_mmc_clk_init(struct meson_host *host) /* init SD_EMMC_CLOCK to sane defaults w/min clock rate */ clk_reg = 0; - clk_reg |= FIELD_PREP(CLK_CORE_PHASE_MASK, host->tp.core_phase); - clk_reg |= FIELD_PREP(CLK_TX_PHASE_MASK, host->tp.tx_phase); - clk_reg |= FIELD_PREP(CLK_RX_PHASE_MASK, host->tp.rx_phase); clk_reg |= CLK_DIV_MASK; clk_reg |= CLK_ALWAYS_ON; writel(clk_reg, host->regs + SD_EMMC_CLOCK); @@ -409,31 +435,6 @@ static int meson_mmc_clk_init(struct meson_host *host) return clk_prepare_enable(host->signal_clk); } -static void meson_mmc_set_tuning_params(struct mmc_host *mmc) -{ - struct meson_host *host = mmc_priv(mmc); - u32 regval; - - /* stop clock */ - regval = readl(host->regs + SD_EMMC_CFG); - regval |= CFG_STOP_CLOCK; - writel(regval, host->regs + SD_EMMC_CFG); - - regval = readl(host->regs + SD_EMMC_CLOCK); - regval &= ~CLK_CORE_PHASE_MASK; - regval |= FIELD_PREP(CLK_CORE_PHASE_MASK, host->tp.core_phase); - regval &= ~CLK_TX_PHASE_MASK; - regval |= FIELD_PREP(CLK_TX_PHASE_MASK, host->tp.tx_phase); - regval &= ~CLK_RX_PHASE_MASK; - regval |= FIELD_PREP(CLK_RX_PHASE_MASK, host->tp.rx_phase); - writel(regval, host->regs + SD_EMMC_CLOCK); - - /* start clock */ - regval = readl(host->regs + SD_EMMC_CFG); - regval &= ~CFG_STOP_CLOCK; - writel(regval, host->regs + SD_EMMC_CFG); -} - static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) { struct meson_host *host = mmc_priv(mmc); @@ -472,6 +473,7 @@ static void meson_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios) host->vqmmc_enabled = true; } + meson_mmc_clk_phase_dflt(host); break; } @@ -797,27 +799,134 @@ static irqreturn_t meson_mmc_irq_thread(int irq, void *dev_id) return IRQ_HANDLED; } +static void meson_mmc_apply_rx_phase_delay(struct meson_host *host, + unsigned int phase, + unsigned int delay) +{ + u32 val; + + val = readl(host->regs + SD_EMMC_CLOCK); + val &= ~(CLK_RX_PHASE_MASK | CLK_RX_DELAY_MASK); + val |= FIELD_PREP(CLK_RX_PHASE_MASK, phase); + val |= FIELD_PREP(CLK_RX_DELAY_MASK, delay); + writel(val, host->regs + SD_EMMC_CLOCK); +} + + +static void meson_mmc_set_rx_phase(struct meson_host *host, + unsigned long period_ps, + unsigned int phase) +{ + uint64_t p; + unsigned long r, d; + + /* + * First compute the phase index (p), the remainder (r) is the part + * we'll try to acheive using 200 ps delays (d). + */ + p = (phase % 360); + r = do_div(p, (360 / CLK_PHASE_NUM)); + d = DIV_ROUND_CLOSEST((r * period_ps), (CLK_DELAY_STEP_PS * 360)); + + if (d > CLK_DELAY_MAX) + d = CLK_DELAY_MAX; + + meson_mmc_apply_rx_phase_delay(host, p, d); +} + +static void meson_mmc_shift_map(unsigned long *map, unsigned long shift) +{ + DECLARE_BITMAP(left, CLK_PHASE_POINT_NUM); + DECLARE_BITMAP(right, CLK_PHASE_POINT_NUM); + + /* + * shift the bitmap right and reintroduce the dropped bits on the left + * of the bitmap + */ + bitmap_shift_right(right, map, shift, CLK_PHASE_POINT_NUM); + bitmap_shift_left(left, map, CLK_PHASE_POINT_NUM - shift, + CLK_PHASE_POINT_NUM); + bitmap_or(map, left, right, CLK_PHASE_POINT_NUM); +} + +static void meson_mmc_find_next_region(unsigned long *map, + unsigned long *start, + unsigned long *stop) +{ + *start = find_next_bit(map, CLK_PHASE_POINT_NUM, *start); + *stop = find_next_zero_bit(map, CLK_PHASE_POINT_NUM, *start); +} + +static int meson_mmc_find_tuning_point(unsigned long *test) +{ + unsigned long shift, stop, offset = 0, start = 0, size = 0; + + /* Get the all good/all bad situation out the way */ + if (bitmap_full(test, CLK_PHASE_POINT_NUM)) + return 0; /* All points are good so point 0 will do */ + else if (bitmap_empty(test, CLK_PHASE_POINT_NUM)) + return -EINVAL; /* No successful tuning point */ + + /* + * Now we know there is a least one region find. Make sure it does + * not wrap by the shifting the bitmap if necessary + */ + shift = find_first_zero_bit(test, CLK_PHASE_POINT_NUM); + if (shift != 0) + meson_mmc_shift_map(test, shift); + + while (start < CLK_PHASE_POINT_NUM) { + meson_mmc_find_next_region(test, &start, &stop); + + if ((stop - start) > size) { + offset = start; + size = stop - start; + } + + start = stop; + } + + /* Get the center point of the region */ + offset += (size / 2); + + /* Shift the result back */ + offset = (offset + shift) % CLK_PHASE_POINT_NUM; + + return offset; +} + static int meson_mmc_execute_tuning(struct mmc_host *mmc, u32 opcode) { struct meson_host *host = mmc_priv(mmc); - struct meson_tuning_params tp_old = host->tp; - int ret = -EINVAL, i, cmd_error; - - dev_info(mmc_dev(mmc), "(re)tuning...\n"); - - for (i = CLK_PHASE_0; i <= CLK_PHASE_270; i++) { - host->tp.rx_phase = i; - /* exclude the active parameter set if retuning */ - if (!memcmp(&tp_old, &host->tp, sizeof(tp_old)) && - mmc->doing_retune) - continue; - meson_mmc_set_tuning_params(mmc); - ret = mmc_send_tuning(mmc, opcode, &cmd_error); - if (!ret) - break; + int point, cmd_error; + unsigned long period_ps; + DECLARE_BITMAP(test, CLK_PHASE_POINT_NUM); + + dev_dbg(mmc_dev(mmc), "(re)tuning rx phase/delay...\n"); + meson_mmc_clk_phase_dflt(host); + + /* Get period */ + period_ps = DIV_ROUND_UP((unsigned long)NSEC_PER_SEC * 1000, + clk_get_rate(host->signal_clk)); + + /* Explore tuning points */ + for (point = 0; point < CLK_PHASE_POINT_NUM; point++) { + meson_mmc_set_rx_phase(host, period_ps, point * CLK_PHASE_STEP); + if (!mmc_send_tuning(mmc, opcode, &cmd_error)) + set_bit(point, test); } - return ret; + /* Find the optimal tuning point and apply it */ + point = meson_mmc_find_tuning_point(test); + if (point < 0) { + dev_warn(mmc_dev(mmc), "phase/delay tuning failed\n"); + return point; + } + + dev_dbg(mmc_dev(mmc), "tuning successful: point %d\n", point); + meson_mmc_set_rx_phase(host, period_ps, point * CLK_PHASE_STEP); + + return 0; } /* @@ -921,10 +1030,6 @@ static int meson_mmc_probe(struct platform_device *pdev) if (ret) goto free_host; - host->tp.core_phase = CLK_PHASE_180; - host->tp.tx_phase = CLK_PHASE_0; - host->tp.rx_phase = CLK_PHASE_0; - ret = meson_mmc_clk_init(host); if (ret) goto err_core_clk;