blob: cc9a5450e0ce443855347a1823e913967352d933 [file] [log] [blame]
Finley Xiao20d52a02019-09-25 17:57:49 +02001// SPDX-License-Identifier: GPL-2.0
2/*
3 * Copyright (c) 2019 Fuzhou Rockchip Electronics Co., Ltd
4 */
5
6#include <common.h>
7#include <asm/io.h>
8#include <command.h>
9#include <dm.h>
10#include <linux/bitops.h>
11#include <linux/delay.h>
12#include <misc.h>
13
14/* OTP Register Offsets */
15#define OTPC_SBPI_CTRL 0x0020
16#define OTPC_SBPI_CMD_VALID_PRE 0x0024
17#define OTPC_SBPI_CS_VALID_PRE 0x0028
18#define OTPC_SBPI_STATUS 0x002C
19#define OTPC_USER_CTRL 0x0100
20#define OTPC_USER_ADDR 0x0104
21#define OTPC_USER_ENABLE 0x0108
22#define OTPC_USER_QP 0x0120
23#define OTPC_USER_Q 0x0124
24#define OTPC_INT_STATUS 0x0304
25#define OTPC_SBPI_CMD0_OFFSET 0x1000
26#define OTPC_SBPI_CMD1_OFFSET 0x1004
27
28/* OTP Register bits and masks */
29#define OTPC_USER_ADDR_MASK GENMASK(31, 16)
30#define OTPC_USE_USER BIT(0)
31#define OTPC_USE_USER_MASK GENMASK(16, 16)
32#define OTPC_USER_FSM_ENABLE BIT(0)
33#define OTPC_USER_FSM_ENABLE_MASK GENMASK(16, 16)
34#define OTPC_SBPI_DONE BIT(1)
35#define OTPC_USER_DONE BIT(2)
36
37#define SBPI_DAP_ADDR 0x02
38#define SBPI_DAP_ADDR_SHIFT 8
39#define SBPI_DAP_ADDR_MASK GENMASK(31, 24)
40#define SBPI_CMD_VALID_MASK GENMASK(31, 16)
41#define SBPI_DAP_CMD_WRF 0xC0
42#define SBPI_DAP_REG_ECC 0x3A
43#define SBPI_ECC_ENABLE 0x00
44#define SBPI_ECC_DISABLE 0x09
45#define SBPI_ENABLE BIT(0)
46#define SBPI_ENABLE_MASK GENMASK(16, 16)
47
48#define OTPC_TIMEOUT 10000
49
Simon Glassb75b15b2020-12-03 16:55:23 -070050struct rockchip_otp_plat {
Finley Xiao20d52a02019-09-25 17:57:49 +020051 void __iomem *base;
52 unsigned long secure_conf_base;
53 unsigned long otp_mask_base;
54};
55
Simon Glassb75b15b2020-12-03 16:55:23 -070056static int rockchip_otp_wait_status(struct rockchip_otp_plat *otp,
Finley Xiao20d52a02019-09-25 17:57:49 +020057 u32 flag)
58{
59 int delay = OTPC_TIMEOUT;
60
61 while (!(readl(otp->base + OTPC_INT_STATUS) & flag)) {
62 udelay(1);
63 delay--;
64 if (delay <= 0) {
65 printf("%s: wait init status timeout\n", __func__);
66 return -ETIMEDOUT;
67 }
68 }
69
70 /* clean int status */
71 writel(flag, otp->base + OTPC_INT_STATUS);
72
73 return 0;
74}
75
Simon Glassb75b15b2020-12-03 16:55:23 -070076static int rockchip_otp_ecc_enable(struct rockchip_otp_plat *otp,
Finley Xiao20d52a02019-09-25 17:57:49 +020077 bool enable)
78{
79 int ret = 0;
80
81 writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
82 otp->base + OTPC_SBPI_CTRL);
83
84 writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
85 writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
86 otp->base + OTPC_SBPI_CMD0_OFFSET);
87
88 if (enable)
89 writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
90 else
91 writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
92
93 writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
94
95 ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
96 if (ret < 0)
97 printf("%s timeout during ecc_enable\n", __func__);
98
99 return ret;
100}
101
102static int rockchip_px30_otp_read(struct udevice *dev, int offset,
103 void *buf, int size)
104{
Simon Glassb75b15b2020-12-03 16:55:23 -0700105 struct rockchip_otp_plat *otp = dev_get_plat(dev);
Finley Xiao20d52a02019-09-25 17:57:49 +0200106 u8 *buffer = buf;
107 int ret = 0;
108
109 ret = rockchip_otp_ecc_enable(otp, false);
110 if (ret < 0) {
111 printf("%s rockchip_otp_ecc_enable err\n", __func__);
112 return ret;
113 }
114
115 writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
116 udelay(5);
117 while (size--) {
118 writel(offset++ | OTPC_USER_ADDR_MASK,
119 otp->base + OTPC_USER_ADDR);
120 writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
121 otp->base + OTPC_USER_ENABLE);
122
123 ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
124 if (ret < 0) {
125 printf("%s timeout during read setup\n", __func__);
126 goto read_end;
127 }
128
129 *buffer++ = readb(otp->base + OTPC_USER_Q);
130 }
131
132read_end:
133 writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
134
135 return ret;
136}
137
138static int rockchip_otp_read(struct udevice *dev, int offset,
139 void *buf, int size)
140{
141 return rockchip_px30_otp_read(dev, offset, buf, size);
142}
143
144static const struct misc_ops rockchip_otp_ops = {
145 .read = rockchip_otp_read,
146};
147
Simon Glassaad29ae2020-12-03 16:55:21 -0700148static int rockchip_otp_of_to_plat(struct udevice *dev)
Finley Xiao20d52a02019-09-25 17:57:49 +0200149{
Simon Glassb75b15b2020-12-03 16:55:23 -0700150 struct rockchip_otp_plat *otp = dev_get_plat(dev);
Finley Xiao20d52a02019-09-25 17:57:49 +0200151
152 otp->base = dev_read_addr_ptr(dev);
153
154 return 0;
155}
156
157static const struct udevice_id rockchip_otp_ids[] = {
158 {
159 .compatible = "rockchip,px30-otp",
160 .data = (ulong)&rockchip_px30_otp_read,
161 },
162 {
163 .compatible = "rockchip,rk3308-otp",
164 .data = (ulong)&rockchip_px30_otp_read,
165 },
166 {}
167};
168
169U_BOOT_DRIVER(rockchip_otp) = {
170 .name = "rockchip_otp",
171 .id = UCLASS_MISC,
172 .of_match = rockchip_otp_ids,
173 .ops = &rockchip_otp_ops,
Simon Glassaad29ae2020-12-03 16:55:21 -0700174 .of_to_plat = rockchip_otp_of_to_plat,
Simon Glassb75b15b2020-12-03 16:55:23 -0700175 .plat_auto = sizeof(struct rockchip_otp_plat),
Finley Xiao20d52a02019-09-25 17:57:49 +0200176};