From patchwork Fri Aug 26 07:36:31 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Finley Xiao X-Patchwork-Id: 9300927 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 0209B601C0 for ; Fri, 26 Aug 2016 07:41:56 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id EA2E72952B for ; Fri, 26 Aug 2016 07:41:55 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id DE97C2957A; Fri, 26 Aug 2016 07:41:55 +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=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 4A8862952B for ; Fri, 26 Aug 2016 07:41:55 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.85_2 #1 (Red Hat Linux)) id 1bdBly-0007Q5-K9; Fri, 26 Aug 2016 07:41:54 +0000 Received: from regular1.263xmail.com ([211.150.99.141]) by bombadil.infradead.org with esmtps (Exim 4.85_2 #1 (Red Hat Linux)) id 1bdBlZ-00078c-Lt; Fri, 26 Aug 2016 07:41:32 +0000 Received: from finley.xiao?rock-chips.com (unknown [192.168.167.159]) by regular1.263xmail.com (Postfix) with ESMTP id 6B41D69; Fri, 26 Aug 2016 15:41:05 +0800 (CST) X-263anti-spam: KSV:0; X-MAIL-GRAY: 0 X-MAIL-DELIVERY: 1 X-KSVirus-check: 0 X-ABS-CHECKED: 4 X-ADDR-CHECKED: 0 Received: from localhost.localdomain (localhost.localdomain [127.0.0.1]) by smtp.263.net (Postfix) with ESMTP id 55381363F; Fri, 26 Aug 2016 15:40:29 +0800 (CST) X-RL-SENDER: finley.xiao@rock-chips.com X-FST-TO: srinivas.kandagatla@linaro.org X-SENDER-IP: 58.22.7.114 X-LOGIN-NAME: finley.xiao@rock-chips.com X-UNIQUE-TAG: <357385b984ba3d53713097eb2ff23661> X-ATTACHMENT-NUM: 0 X-SENDER: xf@rock-chips.com X-DNS-TYPE: 0 Received: from unknown (unknown [58.22.7.114]) by smtp.263.net (Postfix) whith SMTP id 7553C8WBLP; Fri, 26 Aug 2016 15:41:02 +0800 (CST) From: Finley Xiao To: srinivas.kandagatla@linaro.org, maxime.ripard@free-electrons.com, robh+dt@kernel.org, mark.rutland@arm.com, heiko@sntech.de, linux@armlinux.org.uk, catalin.marinas@arm.com, will.deacon@arm.com, dianders@chromium.org Subject: [PATCH v3 3/3] nvmem: rockchip-efuse: add rk3399-efuse support Date: Fri, 26 Aug 2016 00:36:31 -0700 Message-Id: <1472196991-8529-4-git-send-email-finley.xiao@rock-chips.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1472196991-8529-1-git-send-email-finley.xiao@rock-chips.com> References: <1472196991-8529-1-git-send-email-finley.xiao@rock-chips.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20160826_004130_734308_079C8726 X-CRM114-Status: GOOD ( 13.70 ) X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.20 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: huangtao@rock-chips.com, devicetree@vger.kernel.org, linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, tony.xie@rock-chips.com, Finley Xiao , cl@rock-chips.com, jay.xu@rock-chips.com, linux-arm-kernel@lists.infradead.org, wxt@rock-chips.com MIME-Version: 1.0 Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP 1) the efuse timing of rk3399 is different from earlier SoCs. 2) rk3399-efuse is organized as 32bits by 32 one-time programmable electrical fuses, the efuse of earlier SoCs is organized as 32bits by 8 one-time programmable electrical fuses with random access interface. This patch adds a new read function for rk3399-efuse. Signed-off-by: Finley Xiao Reviewed-by: Heiko Stuebner --- drivers/nvmem/rockchip-efuse.c | 131 +++++++++++++++++++++++++++++++++++------ 1 file changed, 112 insertions(+), 19 deletions(-) diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c index 4d3f391..2fb6c34 100644 --- a/drivers/nvmem/rockchip-efuse.c +++ b/drivers/nvmem/rockchip-efuse.c @@ -22,17 +22,29 @@ #include #include #include +#include #include -#define EFUSE_A_SHIFT 6 -#define EFUSE_A_MASK 0x3ff -#define EFUSE_PGENB BIT(3) -#define EFUSE_LOAD BIT(2) -#define EFUSE_STROBE BIT(1) -#define EFUSE_CSB BIT(0) - -#define REG_EFUSE_CTRL 0x0000 -#define REG_EFUSE_DOUT 0x0004 +#define RK3288_A_SHIFT 6 +#define RK3288_A_MASK 0x3ff +#define RK3288_PGENB BIT(3) +#define RK3288_LOAD BIT(2) +#define RK3288_STROBE BIT(1) +#define RK3288_CSB BIT(0) + +#define RK3399_A_SHIFT 16 +#define RK3399_A_MASK 0x3ff +#define RK3399_NBYTES 4 +#define RK3399_STROBSFTSEL BIT(9) +#define RK3399_RSB BIT(7) +#define RK3399_PD BIT(5) +#define RK3399_PGENB BIT(3) +#define RK3399_LOAD BIT(2) +#define RK3399_STROBE BIT(1) +#define RK3399_CSB BIT(0) + +#define REG_EFUSE_CTRL 0x0000 +#define REG_EFUSE_DOUT 0x0004 struct rockchip_efuse_chip { struct device *dev; @@ -40,8 +52,8 @@ struct rockchip_efuse_chip { struct clk *clk; }; -static int rockchip_efuse_read(void *context, unsigned int offset, - void *val, size_t bytes) +static int rockchip_rk3288_efuse_read(void *context, unsigned int offset, + void *val, size_t bytes) { struct rockchip_efuse_chip *efuse = context; u8 *buf = val; @@ -53,27 +65,80 @@ static int rockchip_efuse_read(void *context, unsigned int offset, return ret; } - writel(EFUSE_LOAD | EFUSE_PGENB, efuse->base + REG_EFUSE_CTRL); + writel(RK3288_LOAD | RK3288_PGENB, efuse->base + REG_EFUSE_CTRL); udelay(1); while (bytes--) { writel(readl(efuse->base + REG_EFUSE_CTRL) & - (~(EFUSE_A_MASK << EFUSE_A_SHIFT)), + (~(RK3288_A_MASK << RK3288_A_SHIFT)), efuse->base + REG_EFUSE_CTRL); writel(readl(efuse->base + REG_EFUSE_CTRL) | - ((offset++ & EFUSE_A_MASK) << EFUSE_A_SHIFT), + ((offset++ & RK3288_A_MASK) << RK3288_A_SHIFT), efuse->base + REG_EFUSE_CTRL); udelay(1); writel(readl(efuse->base + REG_EFUSE_CTRL) | - EFUSE_STROBE, efuse->base + REG_EFUSE_CTRL); + RK3288_STROBE, efuse->base + REG_EFUSE_CTRL); udelay(1); *buf++ = readb(efuse->base + REG_EFUSE_DOUT); writel(readl(efuse->base + REG_EFUSE_CTRL) & - (~EFUSE_STROBE), efuse->base + REG_EFUSE_CTRL); + (~RK3288_STROBE), efuse->base + REG_EFUSE_CTRL); udelay(1); } /* Switch to standby mode */ - writel(EFUSE_PGENB | EFUSE_CSB, efuse->base + REG_EFUSE_CTRL); + writel(RK3288_PGENB | RK3288_CSB, efuse->base + REG_EFUSE_CTRL); + + clk_disable_unprepare(efuse->clk); + + return 0; +} + +static int rockchip_rk3399_efuse_read(void *context, unsigned int offset, + void *val, size_t bytes) +{ + struct rockchip_efuse_chip *efuse = context; + unsigned int addr_start, addr_end, addr_offset, addr_len; + unsigned int out_value; + unsigned char *buf; + int ret, i = 0; + + ret = clk_prepare_enable(efuse->clk); + if (ret < 0) { + dev_err(efuse->dev, "failed to prepare/enable efuse clk\n"); + return ret; + } + + addr_start = rounddown(offset, RK3399_NBYTES) / RK3399_NBYTES; + addr_end = roundup(offset + bytes, RK3399_NBYTES) / RK3399_NBYTES; + addr_offset = offset % RK3399_NBYTES; + addr_len = addr_end - addr_start; + + buf = kzalloc(sizeof(*buf) * addr_len * RK3399_NBYTES, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + writel(RK3399_LOAD | RK3399_PGENB | RK3399_STROBSFTSEL | RK3399_RSB, + efuse->base + REG_EFUSE_CTRL); + udelay(1); + while (addr_len--) { + writel(readl(efuse->base + REG_EFUSE_CTRL) | RK3399_STROBE | + ((addr_start++ & RK3399_A_MASK) << RK3399_A_SHIFT), + efuse->base + REG_EFUSE_CTRL); + udelay(1); + out_value = readl(efuse->base + REG_EFUSE_DOUT); + writel(readl(efuse->base + REG_EFUSE_CTRL) & (~RK3399_STROBE), + efuse->base + REG_EFUSE_CTRL); + udelay(1); + + memcpy(&buf[i], &out_value, RK3399_NBYTES); + i += RK3399_NBYTES; + } + + /* Switch to standby mode */ + writel(RK3399_PD | RK3399_CSB, efuse->base + REG_EFUSE_CTRL); + + memcpy(val, buf + addr_offset, bytes); + + kfree(buf); clk_disable_unprepare(efuse->clk); @@ -89,7 +154,27 @@ static struct nvmem_config econfig = { }; static const struct of_device_id rockchip_efuse_match[] = { - { .compatible = "rockchip,rockchip-efuse", }, + /* deprecated but kept around for dts binding compatibility */ + { + .compatible = "rockchip,rockchip-efuse", + .data = (void *)&rockchip_rk3288_efuse_read, + }, + { + .compatible = "rockchip,rk3066a-efuse", + .data = (void *)&rockchip_rk3288_efuse_read, + }, + { + .compatible = "rockchip,rk3188-efuse", + .data = (void *)&rockchip_rk3288_efuse_read, + }, + { + .compatible = "rockchip,rk3288-efuse", + .data = (void *)&rockchip_rk3288_efuse_read, + }, + { + .compatible = "rockchip,rk3399-efuse", + .data = (void *)&rockchip_rk3399_efuse_read, + }, { /* sentinel */}, }; MODULE_DEVICE_TABLE(of, rockchip_efuse_match); @@ -99,6 +184,14 @@ static int rockchip_efuse_probe(struct platform_device *pdev) struct resource *res; struct nvmem_device *nvmem; struct rockchip_efuse_chip *efuse; + const struct of_device_id *match; + struct device *dev = &pdev->dev; + + match = of_match_device(dev->driver->of_match_table, dev); + if (!match || !match->data) { + dev_err(dev, "failed to get match data\n"); + return -EINVAL; + } efuse = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_efuse_chip), GFP_KERNEL); @@ -116,7 +209,7 @@ static int rockchip_efuse_probe(struct platform_device *pdev) efuse->dev = &pdev->dev; econfig.size = resource_size(res); - econfig.reg_read = rockchip_efuse_read; + econfig.reg_read = match->data; econfig.priv = efuse; econfig.dev = efuse->dev; nvmem = nvmem_register(&econfig);