From: ZhengShunQian <[email protected]>
Base on nvmem framework, this three patches
implement the eFuse driver of Rockchip SoC.
The data from eFuse contains CPU leakage, chip code and version etc.
The flow of reading data from eFuse is quite simple,
config the CTRL register, write data address to CTRL
register, then data is available in DOUT register.
Although always enable eFuse clock seems awkward,
I can't find a better method to enable clock before
read/write in the nvmem framework.
Appreciate for any suggestions.
ZhengShunQian (3):
nvmem: fix the out-of-range leak in read/write()
nvmem: rockchip-efuse: implement eFuse driver
clk: rockchip: do not gate the efuse256 clock
.../devicetree/bindings/nvmem/rockchip-efuse.txt | 36 +++++
arch/arm/boot/dts/rk3288.dtsi | 13 ++
drivers/clk/rockchip/clk-rk3288.c | 2 +-
drivers/nvmem/Kconfig | 10 ++
drivers/nvmem/Makefile | 2 +
drivers/nvmem/core.c | 4 +-
drivers/nvmem/rockchip-efuse.c | 155 +++++++++++++++++++++
include/dt-bindings/clock/rk3288-cru.h | 1 +
8 files changed, 220 insertions(+), 3 deletions(-)
create mode 100644 Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt
create mode 100644 drivers/nvmem/rockchip-efuse.c
--
1.9.1
From: ZhengShunQian <[email protected]>
The position to read/write must be less than max
register size.
Signed-off-by: ZhengShunQian <[email protected]>
---
drivers/nvmem/core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
index d3c6676..f4af8e5 100644
--- a/drivers/nvmem/core.c
+++ b/drivers/nvmem/core.c
@@ -67,7 +67,7 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
int rc;
/* Stop the user from reading */
- if (pos > nvmem->size)
+ if (pos >= nvmem->size)
return 0;
if (pos + count > nvmem->size)
@@ -92,7 +92,7 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
int rc;
/* Stop the user from writing */
- if (pos > nvmem->size)
+ if (pos >= nvmem->size)
return 0;
if (pos + count > nvmem->size)
--
1.9.1
From: ZhengShunQian <[email protected]>
There are some SoC specified values store in eFuse,
such as the cpu_leakage and cpu_version,
this driver can expose these values to /sys base on nvmem.
Also add the docs of efuse bindings and the rk3288's efuse config.
Signed-off-by: Caesar Wang <[email protected]>
Signed-off-by: ZhengShunQian <[email protected]>
---
.../devicetree/bindings/nvmem/rockchip-efuse.txt | 36 +++++
arch/arm/boot/dts/rk3288.dtsi | 13 ++
drivers/nvmem/Kconfig | 10 ++
drivers/nvmem/Makefile | 2 +
drivers/nvmem/rockchip-efuse.c | 155 +++++++++++++++++++++
5 files changed, 216 insertions(+)
create mode 100644 Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt
create mode 100644 drivers/nvmem/rockchip-efuse.c
diff --git a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt
new file mode 100644
index 0000000..bb487ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt
@@ -0,0 +1,36 @@
+= Rockchip eFuse device tree bindings =
+
+Required properties:
+- compatible: Should be "rockchip,rockchip-efuse"
+- reg: Should contain the registers location and exact eFuse size
+
+= Data cells =
+Are child nodes of eFuse, bindings of which as described in
+bindings/nvmem/nvmem.txt
+
+Example:
+
+ efuse: efuse@ffb40000 {
+ compatible = "rockchip,rockchip-efuse";
+ reg = <0xffb40000 0x20>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ clocks = <&cru PCLK_EFUSE256>;
+ clock-names = "pclk_efuse_256";
+
+ /* Data cells */
+ cpu_leakage: cpu_leakage {
+ reg = <0x17 0x1>;
+ };
+ };
+
+= Data consumers =
+Are device nodes which consume nvmem data cells.
+
+Example:
+
+ cpu_leakage {
+ ...
+ nvmem-cells = <&cpu_leakage>;
+ nvmem-cell-names = "cpu_leakage";
+ };
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 2db91c9..272c0b5 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -749,6 +749,19 @@
interrupts = <GIC_PPI 9 0xf04>;
};
+ efuse: efuse@ffb40000 {
+ compatible = "rockchip,rockchip-efuse";
+ reg = <0xffb40000 0x20>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ clocks = <&cru PCLK_EFUSE256>;
+ clock-names = "pclk_efuse_256";
+
+ cpu_leakage: cpu_leakage {
+ reg = <0x17 0x1>;
+ };
+ };
+
usbphy: phy {
compatible = "rockchip,rk3288-usb-phy";
rockchip,grf = <&grf>;
diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
index 8db2978..98f1fac 100644
--- a/drivers/nvmem/Kconfig
+++ b/drivers/nvmem/Kconfig
@@ -36,4 +36,14 @@ config NVMEM_SUNXI_SID
This driver can also be built as a module. If so, the module
will be called nvmem_sunxi_sid.
+config ROCKCHIP_EFUSE
+ tristate "Rockchip eFuse Support"
+ depends on ARCH_ROCKCHIP || COMPILE_TEST
+ help
+ This is a simple drive to dump specified values of Rockchip SoC
+ from eFuse, such as cpu-leakage.
+
+ This driver can also be built as a module. If so, the module
+ will be called nvmem_rockchip_efuse.
+
endif
diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
index 4328b93..093a528 100644
--- a/drivers/nvmem/Makefile
+++ b/drivers/nvmem/Makefile
@@ -10,3 +10,5 @@ obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o
nvmem_qfprom-y := qfprom.o
obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o
nvmem_sunxi_sid-y := sunxi_sid.o
+obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o
+nvmem_rockchip_efuse-y := rockchip-efuse.o
diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c
new file mode 100644
index 0000000..30ee772
--- /dev/null
+++ b/drivers/nvmem/rockchip-efuse.c
@@ -0,0 +1,155 @@
+/*
+ * Rockchip eFuse Driver
+ *
+ * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
+ * Author: Caesar Wang <[email protected]>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+
+#include <linux/platform_device.h>
+#include <linux/nvmem-provider.h>
+#include <linux/slab.h>
+#include <linux/regmap.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/clk.h>
+
+#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
+
+static int rockchip_efuse_write(void *context, const void *data, size_t count)
+{
+ /* Nothing TBD, Read-Only */
+ return 0;
+}
+
+static int rockchip_efuse_read(void *context,
+ const void *reg, size_t reg_size,
+ void *val, size_t val_size)
+{
+ unsigned int offset = *(u32 *)reg;
+ void __iomem *base = context;
+ u8 *buf = val;
+
+ writel(EFUSE_LOAD | EFUSE_PGENB, base + REG_EFUSE_CTRL);
+ udelay(1);
+ while (val_size) {
+ writel(readl(base + REG_EFUSE_CTRL) &
+ (~(EFUSE_A_MASK << EFUSE_A_SHIFT)),
+ base + REG_EFUSE_CTRL);
+ writel(readl(base + REG_EFUSE_CTRL) |
+ ((offset & EFUSE_A_MASK) << EFUSE_A_SHIFT),
+ base + REG_EFUSE_CTRL);
+ udelay(1);
+ writel(readl(base + REG_EFUSE_CTRL) |
+ EFUSE_STROBE, base + REG_EFUSE_CTRL);
+ udelay(1);
+ *buf++ = readb(base + REG_EFUSE_DOUT);
+ writel(readl(base + REG_EFUSE_CTRL) &
+ (~EFUSE_STROBE), base + REG_EFUSE_CTRL);
+ udelay(1);
+
+ val_size -= 1;
+ offset += 1;
+ }
+
+ /* Switch to standby mode */
+ writel(EFUSE_PGENB | EFUSE_CSB, base + REG_EFUSE_CTRL);
+
+ return 0;
+}
+
+static struct regmap_bus rockchip_efuse_bus = {
+ .read = rockchip_efuse_read,
+ .write = rockchip_efuse_write,
+ .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
+ .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
+};
+
+struct regmap_config rockchip_efuse_regmap_config = {
+ .reg_bits = 32,
+ .reg_stride = 1,
+ .val_bits = 8,
+};
+
+static struct nvmem_config econfig = {
+ .name = "rockchip-efuse",
+ .owner = THIS_MODULE,
+ .read_only = true,
+};
+
+static const struct of_device_id rockchip_efuse_match[] = {
+ { .compatible = "rockchip,rockchip-efuse",},
+ { /* sentinel */},
+};
+MODULE_DEVICE_TABLE(of, rockchip_efuse_match);
+
+int rockchip_efuse_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ struct nvmem_device *nvmem;
+ struct regmap *regmap;
+ void __iomem *base;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(dev, res);
+
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+
+ rockchip_efuse_regmap_config.max_register = resource_size(res) - 1;
+
+ regmap = devm_regmap_init(dev, &rockchip_efuse_bus,
+ base, &rockchip_efuse_regmap_config);
+ if (IS_ERR(regmap)) {
+ dev_err(dev, "regmap init failed\n");
+ return PTR_ERR(regmap);
+ }
+ econfig.dev = dev;
+ nvmem = nvmem_register(&econfig);
+ if (IS_ERR(nvmem))
+ return PTR_ERR(nvmem);
+
+ platform_set_drvdata(pdev, nvmem);
+
+ return 0;
+}
+
+int rockchip_efuse_remove(struct platform_device *pdev)
+{
+ struct nvmem_device *nvmem = platform_get_drvdata(pdev);
+
+ return nvmem_unregister(nvmem);
+}
+
+static struct platform_driver rockchip_efuse_driver = {
+ .probe = rockchip_efuse_probe,
+ .remove = rockchip_efuse_remove,
+ .driver = {
+ .name = "rockchip-efuse",
+ .of_match_table = rockchip_efuse_match,
+ },
+};
+
+module_platform_driver(rockchip_efuse_driver);
+MODULE_DESCRIPTION("rockchip_efuse driver");
+MODULE_LICENSE("GPL v2");
--
1.9.1
From: ZhengShunQian <[email protected]>
Always enable the clock of efuse256. Base on the nvmem framework,
it seems like there is not a good way to enable the clock
when actual needed.
Signed-off-by: ZhengShunQian <[email protected]>
---
drivers/clk/rockchip/clk-rk3288.c | 2 +-
include/dt-bindings/clock/rk3288-cru.h | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
index 0df5bae..84d9218 100644
--- a/drivers/clk/rockchip/clk-rk3288.c
+++ b/drivers/clk/rockchip/clk-rk3288.c
@@ -647,7 +647,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
GATE(0, "pclk_efuse_1024", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 2, GFLAGS),
GATE(PCLK_TZPC, "pclk_tzpc", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 3, GFLAGS),
GATE(PCLK_UART2, "pclk_uart2", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 9, GFLAGS),
- GATE(0, "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS),
+ GATE(PCLK_EFUSE256, "pclk_efuse_256", "pclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 10, GFLAGS),
GATE(PCLK_RKPWM, "pclk_rkpwm", "pclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 11, GFLAGS),
/* ddrctrl [DDR Controller PHY clock] gates */
diff --git a/include/dt-bindings/clock/rk3288-cru.h b/include/dt-bindings/clock/rk3288-cru.h
index c719aac..ab74d5e 100644
--- a/include/dt-bindings/clock/rk3288-cru.h
+++ b/include/dt-bindings/clock/rk3288-cru.h
@@ -164,6 +164,7 @@
#define PCLK_DDRUPCTL1 366
#define PCLK_PUBL1 367
#define PCLK_WDT 368
+#define PCLK_EFUSE256 369
/* hclk gates */
#define HCLK_GPS 448
--
1.9.1
Hi,
Am Montag, 10. August 2015, 11:22:43 schrieb Shunqian Zheng:
> From: ZhengShunQian <[email protected]>
>
> Always enable the clock of efuse256. Base on the nvmem framework,
> it seems like there is not a good way to enable the clock
> when actual needed.
>
> Signed-off-by: ZhengShunQian <[email protected]>
actually regmap already provides a handle to have a clock for mmio-based
regmaps ... take a look at devm_regmap_init_mmio_clk() [0]
If this doesn't help, you can also simply clk_get and clk_prepare_enable the
clock in your rockchip_efuse_probe() and disable in rockchip_efuse_remove().
But I certainly don't want to extend the range of clocks magically staying
enabled through the ccf.
Heiko
[0] http://lxr.free-electrons.com/source/drivers/base/regmap/regmap-mmio.c#L336
> ---
> drivers/clk/rockchip/clk-rk3288.c | 2 +-
> include/dt-bindings/clock/rk3288-cru.h | 1 +
> 2 files changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/rockchip/clk-rk3288.c
> b/drivers/clk/rockchip/clk-rk3288.c index 0df5bae..84d9218 100644
> --- a/drivers/clk/rockchip/clk-rk3288.c
> +++ b/drivers/clk/rockchip/clk-rk3288.c
> @@ -647,7 +647,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[]
> __initdata = { GATE(0, "pclk_efuse_1024", "pclk_cpu", 0,
> RK3288_CLKGATE_CON(11), 2, GFLAGS), GATE(PCLK_TZPC, "pclk_tzpc",
> "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 3, GFLAGS), GATE(PCLK_UART2,
> "pclk_uart2", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 9, GFLAGS), - GATE(0,
> "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS),
> + GATE(PCLK_EFUSE256, "pclk_efuse_256", "pclk_cpu", CLK_IGNORE_UNUSED,
> RK3288_CLKGATE_CON(11), 10, GFLAGS), GATE(PCLK_RKPWM, "pclk_rkpwm",
> "pclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 11, GFLAGS),
>
> /* ddrctrl [DDR Controller PHY clock] gates */
> diff --git a/include/dt-bindings/clock/rk3288-cru.h
> b/include/dt-bindings/clock/rk3288-cru.h index c719aac..ab74d5e 100644
> --- a/include/dt-bindings/clock/rk3288-cru.h
> +++ b/include/dt-bindings/clock/rk3288-cru.h
> @@ -164,6 +164,7 @@
> #define PCLK_DDRUPCTL1 366
> #define PCLK_PUBL1 367
> #define PCLK_WDT 368
> +#define PCLK_EFUSE256 369
>
> /* hclk gates */
> #define HCLK_GPS 448
Hi Heiko,
On 2015年08月10日 16:08, Heiko Stübner wrote:
> Hi,
>
> Am Montag, 10. August 2015, 11:22:43 schrieb Shunqian Zheng:
>> From: ZhengShunQian <[email protected]>
>>
>> Always enable the clock of efuse256. Base on the nvmem framework,
>> it seems like there is not a good way to enable the clock
>> when actual needed.
>>
>> Signed-off-by: ZhengShunQian <[email protected]>
> actually regmap already provides a handle to have a clock for mmio-based
> regmaps ... take a look at devm_regmap_init_mmio_clk() [0]
Srinivas also suggested devm_regmap_init_mmio_clk() too, but unfortunately
mmio uses its own .read/.write callback that not suitable for eFuse.
>
> If this doesn't help, you can also simply clk_get and clk_prepare_enable the
> clock in your rockchip_efuse_probe() and disable in rockchip_efuse_remove().
Sure, I will use this way.
Thank you!!
>
>
> But I certainly don't want to extend the range of clocks magically staying
> enabled through the ccf.
>
>
> Heiko
>
>
> [0] http://lxr.free-electrons.com/source/drivers/base/regmap/regmap-mmio.c#L336
>
>
>> ---
>> drivers/clk/rockchip/clk-rk3288.c | 2 +-
>> include/dt-bindings/clock/rk3288-cru.h | 1 +
>> 2 files changed, 2 insertions(+), 1 deletion(-)
>>
>> diff --git a/drivers/clk/rockchip/clk-rk3288.c
>> b/drivers/clk/rockchip/clk-rk3288.c index 0df5bae..84d9218 100644
>> --- a/drivers/clk/rockchip/clk-rk3288.c
>> +++ b/drivers/clk/rockchip/clk-rk3288.c
>> @@ -647,7 +647,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[]
>> __initdata = { GATE(0, "pclk_efuse_1024", "pclk_cpu", 0,
>> RK3288_CLKGATE_CON(11), 2, GFLAGS), GATE(PCLK_TZPC, "pclk_tzpc",
>> "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 3, GFLAGS), GATE(PCLK_UART2,
>> "pclk_uart2", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 9, GFLAGS), - GATE(0,
>> "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS),
>> + GATE(PCLK_EFUSE256, "pclk_efuse_256", "pclk_cpu", CLK_IGNORE_UNUSED,
>> RK3288_CLKGATE_CON(11), 10, GFLAGS), GATE(PCLK_RKPWM, "pclk_rkpwm",
>> "pclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 11, GFLAGS),
>>
>> /* ddrctrl [DDR Controller PHY clock] gates */
>> diff --git a/include/dt-bindings/clock/rk3288-cru.h
>> b/include/dt-bindings/clock/rk3288-cru.h index c719aac..ab74d5e 100644
>> --- a/include/dt-bindings/clock/rk3288-cru.h
>> +++ b/include/dt-bindings/clock/rk3288-cru.h
>> @@ -164,6 +164,7 @@
>> #define PCLK_DDRUPCTL1 366
>> #define PCLK_PUBL1 367
>> #define PCLK_WDT 368
>> +#define PCLK_EFUSE256 369
>>
>> /* hclk gates */
>> #define HCLK_GPS 448
>
> _______________________________________________
> Linux-rockchip mailing list
> [email protected]
> http://lists.infradead.org/mailman/listinfo/linux-rockchip
>
>
On 10/08/15 04:22, Shunqian Zheng wrote:
> From: ZhengShunQian <[email protected]>
>
> Always enable the clock of efuse256. Base on the nvmem framework,
> it seems like there is not a good way to enable the clock
> when actual needed.
No, thats not true. NVMEM does not mandate anything, it give more
flexibity to providers instead.
What ever this patch is in wrong direction to solve the issue.
We have two options to use clocks for providers, one use
devm_regmap_init_mmio_clk() Or
Have your own context structure like
struct rockchip_context{
void __iomem *base
struct clk *efuse_clk;
};
Then in read/write manage the clock as required.
--srini
>
> Signed-off-by: ZhengShunQian <[email protected]>
> ---
> drivers/clk/rockchip/clk-rk3288.c | 2 +-
> include/dt-bindings/clock/rk3288-cru.h | 1 +
> 2 files changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/clk/rockchip/clk-rk3288.c b/drivers/clk/rockchip/clk-rk3288.c
> index 0df5bae..84d9218 100644
> --- a/drivers/clk/rockchip/clk-rk3288.c
> +++ b/drivers/clk/rockchip/clk-rk3288.c
> @@ -647,7 +647,7 @@ static struct rockchip_clk_branch rk3288_clk_branches[] __initdata = {
> GATE(0, "pclk_efuse_1024", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 2, GFLAGS),
> GATE(PCLK_TZPC, "pclk_tzpc", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 3, GFLAGS),
> GATE(PCLK_UART2, "pclk_uart2", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 9, GFLAGS),
> - GATE(0, "pclk_efuse_256", "pclk_cpu", 0, RK3288_CLKGATE_CON(11), 10, GFLAGS),
> + GATE(PCLK_EFUSE256, "pclk_efuse_256", "pclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 10, GFLAGS),
> GATE(PCLK_RKPWM, "pclk_rkpwm", "pclk_cpu", CLK_IGNORE_UNUSED, RK3288_CLKGATE_CON(11), 11, GFLAGS),
>
> /* ddrctrl [DDR Controller PHY clock] gates */
> diff --git a/include/dt-bindings/clock/rk3288-cru.h b/include/dt-bindings/clock/rk3288-cru.h
> index c719aac..ab74d5e 100644
> --- a/include/dt-bindings/clock/rk3288-cru.h
> +++ b/include/dt-bindings/clock/rk3288-cru.h
> @@ -164,6 +164,7 @@
> #define PCLK_DDRUPCTL1 366
> #define PCLK_PUBL1 367
> #define PCLK_WDT 368
> +#define PCLK_EFUSE256 369
>
> /* hclk gates */
> #define HCLK_GPS 448
>
On 10/08/15 04:22, Shunqian Zheng wrote:
> From: ZhengShunQian <[email protected]>
>
> The position to read/write must be less than max
> register size.
>
> Signed-off-by: ZhengShunQian <[email protected]>
> ---
> drivers/nvmem/core.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/nvmem/core.c b/drivers/nvmem/core.c
> index d3c6676..f4af8e5 100644
> --- a/drivers/nvmem/core.c
> +++ b/drivers/nvmem/core.c
> @@ -67,7 +67,7 @@ static ssize_t bin_attr_nvmem_read(struct file *filp, struct kobject *kobj,
> int rc;
>
> /* Stop the user from reading */
> - if (pos > nvmem->size)
> + if (pos >= nvmem->size)
> return 0;
>
> if (pos + count > nvmem->size)
> @@ -92,7 +92,7 @@ static ssize_t bin_attr_nvmem_write(struct file *filp, struct kobject *kobj,
> int rc;
>
> /* Stop the user from writing */
> - if (pos > nvmem->size)
> + if (pos >= nvmem->size)
> return 0;
>
> if (pos + count > nvmem->size)
>
This looks good,
Acked-by: Srinivas Kandagatla <[email protected]>
Hi Shunqian,
On 10/08/15 04:22, Shunqian Zheng wrote:
> From: ZhengShunQian <[email protected]>
>
> There are some SoC specified values store in eFuse,
> such as the cpu_leakage and cpu_version,
> this driver can expose these values to /sys base on nvmem.
>
> Also add the docs of efuse bindings and the rk3288's efuse config.
>
> Signed-off-by: Caesar Wang <[email protected]>
> Signed-off-by: ZhengShunQian <[email protected]>
> ---
> .../devicetree/bindings/nvmem/rockchip-efuse.txt | 36 +++++
> arch/arm/boot/dts/rk3288.dtsi | 13 ++
> drivers/nvmem/Kconfig | 10 ++
> drivers/nvmem/Makefile | 2 +
> drivers/nvmem/rockchip-efuse.c | 155 +++++++++++++++++++++
> 5 files changed, 216 insertions(+)
> create mode 100644 Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt
> create mode 100644 drivers/nvmem/rockchip-efuse.c
>
Please split this patch into alteast 3 parts, one for dts, one for
documentation, one for driver.
> diff --git a/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt
> new file mode 100644
> index 0000000..bb487ec
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/nvmem/rockchip-efuse.txt
> @@ -0,0 +1,36 @@
> += Rockchip eFuse device tree bindings =
> +
> +Required properties:
> +- compatible: Should be "rockchip,rockchip-efuse"
> +- reg: Should contain the registers location and exact eFuse size
Why did you not mention the clocks property here?
> +
> += Data cells =
> +Are child nodes of eFuse, bindings of which as described in
> +bindings/nvmem/nvmem.txt
> +
> +Example:
> +
> + efuse: efuse@ffb40000 {
> + compatible = "rockchip,rockchip-efuse";
> + reg = <0xffb40000 0x20>;
> + #address-cells = <1>;
> + #size-cells = <1>;
> + clocks = <&cru PCLK_EFUSE256>;
> + clock-names = "pclk_efuse_256";
> +
> + /* Data cells */
> + cpu_leakage: cpu_leakage {
> + reg = <0x17 0x1>;
> + };
> + };
> +
> += Data consumers =
> +Are device nodes which consume nvmem data cells.
> +
> +Example:
> +
> + cpu_leakage {
> + ...
> + nvmem-cells = <&cpu_leakage>;
> + nvmem-cell-names = "cpu_leakage";
> + };
> diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
> index 2db91c9..272c0b5 100644
> --- a/arch/arm/boot/dts/rk3288.dtsi
> +++ b/arch/arm/boot/dts/rk3288.dtsi
> @@ -749,6 +749,19 @@
> interrupts = <GIC_PPI 9 0xf04>;
> };
>
> + efuse: efuse@ffb40000 {
> + compatible = "rockchip,rockchip-efuse";
> + reg = <0xffb40000 0x20>;
> + #address-cells = <1>;
> + #size-cells = <1>;
> + clocks = <&cru PCLK_EFUSE256>;
> + clock-names = "pclk_efuse_256";
> +
> + cpu_leakage: cpu_leakage {
> + reg = <0x17 0x1>;
> + };
> + };
> +
> usbphy: phy {
> compatible = "rockchip,rk3288-usb-phy";
> rockchip,grf = <&grf>;
> diff --git a/drivers/nvmem/Kconfig b/drivers/nvmem/Kconfig
> index 8db2978..98f1fac 100644
> --- a/drivers/nvmem/Kconfig
> +++ b/drivers/nvmem/Kconfig
> @@ -36,4 +36,14 @@ config NVMEM_SUNXI_SID
> This driver can also be built as a module. If so, the module
> will be called nvmem_sunxi_sid.
>
> +config ROCKCHIP_EFUSE
> + tristate "Rockchip eFuse Support"
> + depends on ARCH_ROCKCHIP || COMPILE_TEST
> + help
> + This is a simple drive to dump specified values of Rockchip SoC
> + from eFuse, such as cpu-leakage.
> +
> + This driver can also be built as a module. If so, the module
> + will be called nvmem_rockchip_efuse.
> +
> endif
> diff --git a/drivers/nvmem/Makefile b/drivers/nvmem/Makefile
> index 4328b93..093a528 100644
> --- a/drivers/nvmem/Makefile
> +++ b/drivers/nvmem/Makefile
> @@ -10,3 +10,5 @@ obj-$(CONFIG_QCOM_QFPROM) += nvmem_qfprom.o
> nvmem_qfprom-y := qfprom.o
> obj-$(CONFIG_NVMEM_SUNXI_SID) += nvmem_sunxi_sid.o
> nvmem_sunxi_sid-y := sunxi_sid.o
> +obj-$(CONFIG_ROCKCHIP_EFUSE) += nvmem_rockchip_efuse.o
> +nvmem_rockchip_efuse-y := rockchip-efuse.o
> diff --git a/drivers/nvmem/rockchip-efuse.c b/drivers/nvmem/rockchip-efuse.c
> new file mode 100644
> index 0000000..30ee772
> --- /dev/null
> +++ b/drivers/nvmem/rockchip-efuse.c
> @@ -0,0 +1,155 @@
> +/*
> + * Rockchip eFuse Driver
> + *
> + * Copyright (c) 2015 Rockchip Electronics Co. Ltd.
> + * Author: Caesar Wang <[email protected]>
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms of version 2 of the GNU General Public License as
> + * published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
> + * more details.
> + */
> +
> +#include <linux/platform_device.h>
> +#include <linux/nvmem-provider.h>
> +#include <linux/slab.h>
> +#include <linux/regmap.h>
> +#include <linux/device.h>
> +#include <linux/io.h>
> +#include <linux/module.h>
> +#include <linux/delay.h>
> +#include <linux/of.h>
> +#include <linux/clk.h>
??
> +
> +#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
> +
> +static int rockchip_efuse_write(void *context, const void *data, size_t count)
> +{
> + /* Nothing TBD, Read-Only */
> + return 0;
> +}
> +
> +static int rockchip_efuse_read(void *context,
> + const void *reg, size_t reg_size,
> + void *val, size_t val_size)
> +{
> + unsigned int offset = *(u32 *)reg;
> + void __iomem *base = context;
> + u8 *buf = val;
As discussed in the "clk: rockchip: do not gate the efuse256 clock"
patch, please get hold of the clock via context and enable/disable as
required.
Other than this the patch is looking good.
Pleas Add Greg KH into the loop so that we can request him to take this
for this merge window.
> +
> + writel(EFUSE_LOAD | EFUSE_PGENB, base + REG_EFUSE_CTRL);
> + udelay(1);
> + while (val_size) {
> + writel(readl(base + REG_EFUSE_CTRL) &
> + (~(EFUSE_A_MASK << EFUSE_A_SHIFT)),
> + base + REG_EFUSE_CTRL);
> + writel(readl(base + REG_EFUSE_CTRL) |
> + ((offset & EFUSE_A_MASK) << EFUSE_A_SHIFT),
> + base + REG_EFUSE_CTRL);
> + udelay(1);
> + writel(readl(base + REG_EFUSE_CTRL) |
> + EFUSE_STROBE, base + REG_EFUSE_CTRL);
> + udelay(1);
> + *buf++ = readb(base + REG_EFUSE_DOUT);
> + writel(readl(base + REG_EFUSE_CTRL) &
> + (~EFUSE_STROBE), base + REG_EFUSE_CTRL);
> + udelay(1);
> +
> + val_size -= 1;
> + offset += 1;
> + }
> +
> + /* Switch to standby mode */
> + writel(EFUSE_PGENB | EFUSE_CSB, base + REG_EFUSE_CTRL);
> +
> + return 0;
> +}
> +
> +static struct regmap_bus rockchip_efuse_bus = {
> + .read = rockchip_efuse_read,
> + .write = rockchip_efuse_write,
> + .reg_format_endian_default = REGMAP_ENDIAN_NATIVE,
> + .val_format_endian_default = REGMAP_ENDIAN_NATIVE,
> +};
> +
> +struct regmap_config rockchip_efuse_regmap_config = {
> + .reg_bits = 32,
> + .reg_stride = 1,
> + .val_bits = 8,
> +};
> +
> +static struct nvmem_config econfig = {
> + .name = "rockchip-efuse",
> + .owner = THIS_MODULE,
> + .read_only = true,
> +};
> +
> +static const struct of_device_id rockchip_efuse_match[] = {
> + { .compatible = "rockchip,rockchip-efuse",},
> + { /* sentinel */},
> +};
> +MODULE_DEVICE_TABLE(of, rockchip_efuse_match);
> +
> +int rockchip_efuse_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct resource *res;
> + struct nvmem_device *nvmem;
> + struct regmap *regmap;
> + void __iomem *base;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + base = devm_ioremap_resource(dev, res);
> +
> + if (IS_ERR(base))
> + return PTR_ERR(base);
> +
> + rockchip_efuse_regmap_config.max_register = resource_size(res) - 1;
> +
> + regmap = devm_regmap_init(dev, &rockchip_efuse_bus,
> + base, &rockchip_efuse_regmap_config);
> + if (IS_ERR(regmap)) {
> + dev_err(dev, "regmap init failed\n");
> + return PTR_ERR(regmap);
> + }
> + econfig.dev = dev;
> + nvmem = nvmem_register(&econfig);
> + if (IS_ERR(nvmem))
> + return PTR_ERR(nvmem);
> +
> + platform_set_drvdata(pdev, nvmem);
> +
> + return 0;
> +}
> +
> +int rockchip_efuse_remove(struct platform_device *pdev)
> +{
> + struct nvmem_device *nvmem = platform_get_drvdata(pdev);
> +
> + return nvmem_unregister(nvmem);
> +}
> +
> +static struct platform_driver rockchip_efuse_driver = {
> + .probe = rockchip_efuse_probe,
> + .remove = rockchip_efuse_remove,
> + .driver = {
> + .name = "rockchip-efuse",
> + .of_match_table = rockchip_efuse_match,
> + },
> +};
> +
> +module_platform_driver(rockchip_efuse_driver);
> +MODULE_DESCRIPTION("rockchip_efuse driver");
> +MODULE_LICENSE("GPL v2");
>