Page MenuHomeFreeBSD

D26847.diff
No OneTemporary

D26847.diff

Index: sys/arm64/rockchip/rk3399_efuse.c
===================================================================
--- sys/arm64/rockchip/rk3399_efuse.c
+++ sys/arm64/rockchip/rk3399_efuse.c
@@ -0,0 +1,259 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 BusyTech
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * RK3399 non-secure efuse driver (read + write mode).
+ * Based on RK3399 TRM part 1, please read it for further details.
+ *
+ * Write mode has very specific hardware requirements: VQPS must be between 1.8
+ * and 1.98V to allow programming bits in efuse. RockPro64 has this line powered
+ * correctly, not sure about other boards.
+ *
+ * Writing bits to efuse array is irreversible! You have been warned.
+ */
+
+#include <sys/param.h>
+#include <sys/kernel.h>
+#include <sys/types.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/rman.h>
+#include <sys/resource.h>
+#include <sys/uio.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/fdt/fdt_common.h>
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include "nvmem_if.h"
+
+/* Registers & bits in registers. */
+#define EFUSE_CTRL 0x0000
+#define EFUSE_CTRL_CSB (1 << 0)
+#define EFUSE_CTRL_STROBE (1 << 1)
+#define EFUSE_CTRL_LOAD (1 << 2)
+#define EFUSE_CTRL_PGENB (1 << 3)
+#define EFUSE_CTRL_PS (1 << 4)
+#define EFUSE_CTRL_PD (1 << 5)
+#define EFUSE_CTRL_MR (1 << 6)
+#define EFUSE_CTRL_RSB (1 << 7)
+#define EFUSE_CTRL_RWL (1 << 8)
+#define EFUSE_CTRL_STROBE_SFT_SEL (1 << 9)
+#define EFUSE_CTRL_ADDR_SHIFT 16
+#define EFUSE_CTRL_ADDR_MASK (0x3ff << EFUSE_CTRL_ADDR_SHIFT)
+#define EFUSE_DOUT 0x0004
+#define EFUSE_RF 0x0008
+#define EFUSE_JTAG_PASS 0x0010
+#define EFUSE_STROBE_FINISH_CTRL 0x0014
+
+#define EFUSE_NUM 32
+#define EFUSE_SIZE 4 /* EFUSE DOUT size in bytes. */
+#define EFUSE_TOTAL_SIZE EFUSE_NUM * EFUSE_SIZE
+#define EFUSE_WRITE_DELAY 13
+
+#define READ4(sc, reg) bus_read_4((sc)->sc_mem_res, (reg))
+#define WRITE4(sc, reg, val) bus_write_4((sc)->sc_mem_res, (reg), (val))
+
+struct rk3399_efuse_softc {
+ device_t sc_dev;
+ struct resource *sc_mem_res;
+ struct mtx sc_lock;
+ clk_t sc_clk;
+ int sc_mem_rid;
+};
+
+static devclass_t rk3399_efuse_devclass;
+
+static int rk3399_efuse_probe(device_t);
+static int rk3399_efuse_attach(device_t);
+
+static int rk3399_efuse_read(device_t, uint32_t, uint32_t, uint8_t *);
+static int rk3399_efuse_write(device_t, uint32_t, uint32_t, uint8_t *);
+
+static int
+rk3399_efuse_read(device_t dev, uint32_t offset, uint32_t size, uint8_t *buffer)
+{
+ struct rk3399_efuse_softc *sc = device_get_softc(dev);
+ uint32_t buf[EFUSE_NUM];
+ uint32_t val;
+ uint32_t ii;
+
+ if (sc == NULL)
+ return (ENXIO);
+
+ if (offset + size > EFUSE_TOTAL_SIZE || size == 0)
+ return (ENOMEM);
+
+ mtx_lock(&sc->sc_lock);
+ WRITE4(sc, EFUSE_CTRL, EFUSE_CTRL_LOAD | EFUSE_CTRL_PGENB |
+ EFUSE_CTRL_STROBE_SFT_SEL | EFUSE_CTRL_RSB);
+ DELAY(1);
+ for (ii = 0; ii < EFUSE_NUM; ii++) {
+ val = READ4(sc, EFUSE_CTRL) | EFUSE_CTRL_STROBE |
+ (ii << EFUSE_CTRL_ADDR_SHIFT);
+ WRITE4(sc, EFUSE_CTRL, val);
+ DELAY(1);
+
+ buf[ii] = READ4(sc, EFUSE_DOUT);
+ }
+ WRITE4(sc, EFUSE_CTRL, EFUSE_CTRL_CSB | EFUSE_CTRL_PD);
+ mtx_unlock(&sc->sc_lock);
+
+ memcpy(buffer, (const uint8_t *)buf + offset, size);
+ return (0);
+}
+
+static int
+rk3399_efuse_write(device_t dev, uint32_t offset, uint32_t size, uint8_t *
+ buffer)
+{
+ /*
+ * Algorithm:
+ * 1) Enable program mode and wait 1 µs.
+ * 2) Locate 1-bits (and their addresses for A9~A0).
+ * 3) For any 1-bit, do following:
+ * set address & STROBE for 13 µs (12 is minimum, add 1)
+ * 4) Disable program mode.
+ */
+ struct rk3399_efuse_softc *sc = device_get_softc(dev);
+ uint32_t buf[EFUSE_NUM];
+ uint32_t val;
+ int ii, jj;
+
+ if (sc == NULL)
+ return (ENXIO);
+
+ if (offset + size > EFUSE_TOTAL_SIZE)
+ return (ENOMEM);
+
+ memset(buf, '\0', sizeof(buf));
+ memcpy((uint8_t *)buf + offset, buffer, size);
+
+ mtx_lock(&sc->sc_lock);
+ WRITE4(sc, EFUSE_CTRL, EFUSE_CTRL_PS | EFUSE_CTRL_RSB |
+ EFUSE_CTRL_STROBE_SFT_SEL);
+ DELAY(1);
+ for (ii = 0; ii < EFUSE_NUM; ii++) {
+ for (jj = 0; jj < EFUSE_SIZE * 8; jj++) {
+ if ((buf[ii] & (1U << jj)) != 0) {
+ /* Compute bit number (0 ... 1023). */
+ const uint32_t addr = ii + jj * EFUSE_SIZE * 8;
+ KASSERT(addr < 1024, ("Invalid bit number"));
+
+ val = addr << EFUSE_CTRL_ADDR_SHIFT;
+
+ WRITE4(sc, EFUSE_CTRL, EFUSE_CTRL_STROBE | val);
+ DELAY(EFUSE_WRITE_DELAY);
+ }
+ }
+ }
+ WRITE4(sc, EFUSE_CTRL, EFUSE_CTRL_CSB | EFUSE_CTRL_PD);
+ mtx_unlock(&sc->sc_lock);
+
+ return (0);
+}
+
+static int
+rk3399_efuse_probe(device_t dev)
+{
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (!ofw_bus_is_compatible(dev, "rockchip,rk3399-efuse"))
+ return (ENXIO);
+
+ device_set_desc(dev, "Rockchip RK3399 fuse (non-secure)");
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+rk3399_efuse_attach(device_t dev)
+{
+ struct rk3399_efuse_softc *sc;
+
+ sc = device_get_softc(dev);
+ sc->sc_dev = dev;
+
+ sc->sc_mem_rid = 0;
+ sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY,
+ &sc->sc_mem_rid, RF_ACTIVE);
+ if (sc->sc_mem_res == NULL) {
+ device_printf(dev, "cannot allocate memory resource\n");
+ goto err_alloc_mem;
+ }
+
+ if (clk_get_by_ofw_index(dev, 0, 0, &sc->sc_clk) != 0) {
+ device_printf(dev, "cannot find clock\n");
+ goto err_no_clock;
+ }
+
+ if (clk_enable(sc->sc_clk) != 0) {
+ device_printf(dev, "cannot enable clock\n");
+ goto err_clock_disabled;
+ }
+
+ mtx_init(&sc->sc_lock, device_get_nameunit(dev), "rk3399_efuse",
+ MTX_DEF);
+ return (bus_generic_attach(dev));
+
+err_clock_disabled:
+ clk_release(sc->sc_clk);
+err_no_clock:
+ bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid,
+ sc->sc_mem_res);
+err_alloc_mem:
+ return (ENXIO);
+}
+
+static device_method_t rk3399_efuse_methods[] = {
+ DEVMETHOD(device_probe, rk3399_efuse_probe),
+ DEVMETHOD(device_attach, rk3399_efuse_attach),
+
+ DEVMETHOD(nvmem_read, rk3399_efuse_read),
+ DEVMETHOD(nvmem_write, rk3399_efuse_write),
+
+ DEVMETHOD_END
+};
+
+static driver_t rk3399_efuse_driver = {
+ "rk3399_efuse",
+ rk3399_efuse_methods,
+ sizeof(struct rk3399_efuse_softc),
+};
+
+DRIVER_MODULE(rk3399_efuse, simplebus, rk3399_efuse_driver,
+ rk3399_efuse_devclass, NULL, NULL);
+MODULE_VERSION(rk3399_efuse, 1);

File Metadata

Mime Type
text/plain
Expires
Tue, Oct 21, 5:17 PM (23 m, 3 s)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
24024164
Default Alt Text
D26847.diff (7 KB)

Event Timeline