Linux Audio

Check our new training course

Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Rockchip OTP Driver
  4 *
  5 * Copyright (c) 2018 Rockchip Electronics Co. Ltd.
  6 * Author: Finley Xiao <finley.xiao@rock-chips.com>
  7 */
  8
  9#include <linux/clk.h>
 10#include <linux/delay.h>
 11#include <linux/device.h>
 12#include <linux/io.h>
 13#include <linux/iopoll.h>
 14#include <linux/module.h>
 15#include <linux/nvmem-provider.h>
 16#include <linux/reset.h>
 17#include <linux/slab.h>
 18#include <linux/of.h>
 19#include <linux/of_platform.h>
 20#include <linux/platform_device.h>
 21
 22/* OTP Register Offsets */
 23#define OTPC_SBPI_CTRL			0x0020
 24#define OTPC_SBPI_CMD_VALID_PRE		0x0024
 25#define OTPC_SBPI_CS_VALID_PRE		0x0028
 26#define OTPC_SBPI_STATUS		0x002C
 27#define OTPC_USER_CTRL			0x0100
 28#define OTPC_USER_ADDR			0x0104
 29#define OTPC_USER_ENABLE		0x0108
 30#define OTPC_USER_Q			0x0124
 31#define OTPC_INT_STATUS			0x0304
 32#define OTPC_SBPI_CMD0_OFFSET		0x1000
 33#define OTPC_SBPI_CMD1_OFFSET		0x1004
 34
 35/* OTP Register bits and masks */
 36#define OTPC_USER_ADDR_MASK		GENMASK(31, 16)
 37#define OTPC_USE_USER			BIT(0)
 38#define OTPC_USE_USER_MASK		GENMASK(16, 16)
 39#define OTPC_USER_FSM_ENABLE		BIT(0)
 40#define OTPC_USER_FSM_ENABLE_MASK	GENMASK(16, 16)
 41#define OTPC_SBPI_DONE			BIT(1)
 42#define OTPC_USER_DONE			BIT(2)
 43
 44#define SBPI_DAP_ADDR			0x02
 45#define SBPI_DAP_ADDR_SHIFT		8
 46#define SBPI_DAP_ADDR_MASK		GENMASK(31, 24)
 47#define SBPI_CMD_VALID_MASK		GENMASK(31, 16)
 48#define SBPI_DAP_CMD_WRF		0xC0
 49#define SBPI_DAP_REG_ECC		0x3A
 50#define SBPI_ECC_ENABLE			0x00
 51#define SBPI_ECC_DISABLE		0x09
 52#define SBPI_ENABLE			BIT(0)
 53#define SBPI_ENABLE_MASK		GENMASK(16, 16)
 54
 55#define OTPC_TIMEOUT			10000
 56
 57/* RK3588 Register */
 58#define RK3588_OTPC_AUTO_CTRL		0x04
 59#define RK3588_OTPC_AUTO_EN		0x08
 60#define RK3588_OTPC_INT_ST		0x84
 61#define RK3588_OTPC_DOUT0		0x20
 62#define RK3588_NO_SECURE_OFFSET		0x300
 63#define RK3588_NBYTES			4
 64#define RK3588_BURST_NUM		1
 65#define RK3588_BURST_SHIFT		8
 66#define RK3588_ADDR_SHIFT		16
 67#define RK3588_AUTO_EN			BIT(0)
 68#define RK3588_RD_DONE			BIT(1)
 69
 70struct rockchip_data {
 71	int size;
 72	const char * const *clks;
 73	int num_clks;
 74	nvmem_reg_read_t reg_read;
 75};
 76
 77struct rockchip_otp {
 78	struct device *dev;
 79	void __iomem *base;
 80	struct clk_bulk_data *clks;
 
 81	struct reset_control *rst;
 82	const struct rockchip_data *data;
 
 
 
 
 
 
 
 
 83};
 84
 85static int rockchip_otp_reset(struct rockchip_otp *otp)
 86{
 87	int ret;
 88
 89	ret = reset_control_assert(otp->rst);
 90	if (ret) {
 91		dev_err(otp->dev, "failed to assert otp phy %d\n", ret);
 92		return ret;
 93	}
 94
 95	udelay(2);
 96
 97	ret = reset_control_deassert(otp->rst);
 98	if (ret) {
 99		dev_err(otp->dev, "failed to deassert otp phy %d\n", ret);
100		return ret;
101	}
102
103	return 0;
104}
105
106static int rockchip_otp_wait_status(struct rockchip_otp *otp,
107				    unsigned int reg, u32 flag)
108{
109	u32 status = 0;
110	int ret;
111
112	ret = readl_poll_timeout_atomic(otp->base + reg, status,
113					(status & flag), 1, OTPC_TIMEOUT);
114	if (ret)
115		return ret;
116
117	/* clean int status */
118	writel(flag, otp->base + reg);
119
120	return 0;
121}
122
123static int rockchip_otp_ecc_enable(struct rockchip_otp *otp, bool enable)
124{
125	int ret = 0;
126
127	writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
128	       otp->base + OTPC_SBPI_CTRL);
129
130	writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
131	writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
132	       otp->base + OTPC_SBPI_CMD0_OFFSET);
133	if (enable)
134		writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
135	else
136		writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
137
138	writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
139
140	ret = rockchip_otp_wait_status(otp, OTPC_INT_STATUS, OTPC_SBPI_DONE);
141	if (ret < 0)
142		dev_err(otp->dev, "timeout during ecc_enable\n");
143
144	return ret;
145}
146
147static int px30_otp_read(void *context, unsigned int offset,
148			 void *val, size_t bytes)
149{
150	struct rockchip_otp *otp = context;
151	u8 *buf = val;
152	int ret;
 
 
 
 
 
 
153
154	ret = rockchip_otp_reset(otp);
155	if (ret) {
156		dev_err(otp->dev, "failed to reset otp phy\n");
157		return ret;
158	}
159
160	ret = rockchip_otp_ecc_enable(otp, false);
161	if (ret < 0) {
162		dev_err(otp->dev, "rockchip_otp_ecc_enable err\n");
163		return ret;
164	}
165
166	writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
167	udelay(5);
168	while (bytes--) {
169		writel(offset++ | OTPC_USER_ADDR_MASK,
170		       otp->base + OTPC_USER_ADDR);
171		writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
172		       otp->base + OTPC_USER_ENABLE);
173		ret = rockchip_otp_wait_status(otp, OTPC_INT_STATUS, OTPC_USER_DONE);
174		if (ret < 0) {
175			dev_err(otp->dev, "timeout during read setup\n");
176			goto read_end;
177		}
178		*buf++ = readb(otp->base + OTPC_USER_Q);
179	}
180
181read_end:
182	writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
183
184	return ret;
185}
186
187static int rk3588_otp_read(void *context, unsigned int offset,
188			   void *val, size_t bytes)
189{
190	struct rockchip_otp *otp = context;
191	unsigned int addr_start, addr_end, addr_len;
192	int ret, i = 0;
193	u32 data;
194	u8 *buf;
195
196	addr_start = round_down(offset, RK3588_NBYTES) / RK3588_NBYTES;
197	addr_end = round_up(offset + bytes, RK3588_NBYTES) / RK3588_NBYTES;
198	addr_len = addr_end - addr_start;
199	addr_start += RK3588_NO_SECURE_OFFSET;
200
201	buf = kzalloc(array_size(addr_len, RK3588_NBYTES), GFP_KERNEL);
202	if (!buf)
203		return -ENOMEM;
204
205	while (addr_len--) {
206		writel((addr_start << RK3588_ADDR_SHIFT) |
207		       (RK3588_BURST_NUM << RK3588_BURST_SHIFT),
208		       otp->base + RK3588_OTPC_AUTO_CTRL);
209		writel(RK3588_AUTO_EN, otp->base + RK3588_OTPC_AUTO_EN);
210
211		ret = rockchip_otp_wait_status(otp, RK3588_OTPC_INT_ST,
212					       RK3588_RD_DONE);
213		if (ret < 0) {
214			dev_err(otp->dev, "timeout during read setup\n");
215			goto read_end;
216		}
217
218		data = readl(otp->base + RK3588_OTPC_DOUT0);
219		memcpy(&buf[i], &data, RK3588_NBYTES);
220
221		i += RK3588_NBYTES;
222		addr_start++;
223	}
224
225	memcpy(val, buf + offset % RK3588_NBYTES, bytes);
226
227read_end:
228	kfree(buf);
229
230	return ret;
231}
232
233static int rockchip_otp_read(void *context, unsigned int offset,
234			     void *val, size_t bytes)
235{
236	struct rockchip_otp *otp = context;
237	int ret;
238
239	if (!otp->data || !otp->data->reg_read)
240		return -EINVAL;
241
242	ret = clk_bulk_prepare_enable(otp->data->num_clks, otp->clks);
243	if (ret < 0) {
244		dev_err(otp->dev, "failed to prepare/enable clks\n");
245		return ret;
246	}
247
248	ret = otp->data->reg_read(context, offset, val, bytes);
249
250	clk_bulk_disable_unprepare(otp->data->num_clks, otp->clks);
251
252	return ret;
253}
254
255static struct nvmem_config otp_config = {
256	.name = "rockchip-otp",
257	.owner = THIS_MODULE,
258	.add_legacy_fixed_of_cells = true,
259	.type = NVMEM_TYPE_OTP,
260	.read_only = true,
261	.stride = 1,
262	.word_size = 1,
263	.reg_read = rockchip_otp_read,
264};
265
266static const char * const px30_otp_clocks[] = {
267	"otp", "apb_pclk", "phy",
268};
269
270static const struct rockchip_data px30_data = {
271	.size = 0x40,
272	.clks = px30_otp_clocks,
273	.num_clks = ARRAY_SIZE(px30_otp_clocks),
274	.reg_read = px30_otp_read,
275};
276
277static const char * const rk3588_otp_clocks[] = {
278	"otp", "apb_pclk", "phy", "arb",
279};
280
281static const struct rockchip_data rk3588_data = {
282	.size = 0x400,
283	.clks = rk3588_otp_clocks,
284	.num_clks = ARRAY_SIZE(rk3588_otp_clocks),
285	.reg_read = rk3588_otp_read,
286};
287
288static const struct of_device_id rockchip_otp_match[] = {
289	{
290		.compatible = "rockchip,px30-otp",
291		.data = &px30_data,
292	},
293	{
294		.compatible = "rockchip,rk3308-otp",
295		.data = &px30_data,
296	},
297	{
298		.compatible = "rockchip,rk3588-otp",
299		.data = &rk3588_data,
300	},
301	{ /* sentinel */ },
302};
303MODULE_DEVICE_TABLE(of, rockchip_otp_match);
304
305static int rockchip_otp_probe(struct platform_device *pdev)
306{
307	struct device *dev = &pdev->dev;
308	struct rockchip_otp *otp;
309	const struct rockchip_data *data;
310	struct nvmem_device *nvmem;
311	int ret, i;
312
313	data = of_device_get_match_data(dev);
314	if (!data)
315		return dev_err_probe(dev, -EINVAL, "failed to get match data\n");
 
 
316
317	otp = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_otp),
318			   GFP_KERNEL);
319	if (!otp)
320		return -ENOMEM;
321
322	otp->data = data;
323	otp->dev = dev;
324	otp->base = devm_platform_ioremap_resource(pdev, 0);
325	if (IS_ERR(otp->base))
326		return dev_err_probe(dev, PTR_ERR(otp->base),
327				     "failed to ioremap resource\n");
328
329	otp->clks = devm_kcalloc(dev, data->num_clks, sizeof(*otp->clks),
330				 GFP_KERNEL);
 
331	if (!otp->clks)
332		return -ENOMEM;
333
334	for (i = 0; i < data->num_clks; ++i)
335		otp->clks[i].id = data->clks[i];
336
337	ret = devm_clk_bulk_get(dev, data->num_clks, otp->clks);
338	if (ret)
339		return dev_err_probe(dev, ret, "failed to get clocks\n");
340
341	otp->rst = devm_reset_control_array_get_exclusive(dev);
342	if (IS_ERR(otp->rst))
343		return dev_err_probe(dev, PTR_ERR(otp->rst),
344				     "failed to get resets\n");
345
346	otp_config.size = data->size;
347	otp_config.priv = otp;
348	otp_config.dev = dev;
349
350	nvmem = devm_nvmem_register(dev, &otp_config);
351	if (IS_ERR(nvmem))
352		return dev_err_probe(dev, PTR_ERR(nvmem),
353				     "failed to register nvmem device\n");
354	return 0;
355}
356
357static struct platform_driver rockchip_otp_driver = {
358	.probe = rockchip_otp_probe,
359	.driver = {
360		.name = "rockchip-otp",
361		.of_match_table = rockchip_otp_match,
362	},
363};
364
365module_platform_driver(rockchip_otp_driver);
366MODULE_DESCRIPTION("Rockchip OTP driver");
367MODULE_LICENSE("GPL v2");
v5.14.15
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * Rockchip OTP Driver
  4 *
  5 * Copyright (c) 2018 Rockchip Electronics Co. Ltd.
  6 * Author: Finley Xiao <finley.xiao@rock-chips.com>
  7 */
  8
  9#include <linux/clk.h>
 10#include <linux/delay.h>
 11#include <linux/device.h>
 12#include <linux/io.h>
 13#include <linux/iopoll.h>
 14#include <linux/module.h>
 15#include <linux/nvmem-provider.h>
 16#include <linux/reset.h>
 17#include <linux/slab.h>
 18#include <linux/of.h>
 19#include <linux/of_platform.h>
 20#include <linux/platform_device.h>
 21
 22/* OTP Register Offsets */
 23#define OTPC_SBPI_CTRL			0x0020
 24#define OTPC_SBPI_CMD_VALID_PRE		0x0024
 25#define OTPC_SBPI_CS_VALID_PRE		0x0028
 26#define OTPC_SBPI_STATUS		0x002C
 27#define OTPC_USER_CTRL			0x0100
 28#define OTPC_USER_ADDR			0x0104
 29#define OTPC_USER_ENABLE		0x0108
 30#define OTPC_USER_Q			0x0124
 31#define OTPC_INT_STATUS			0x0304
 32#define OTPC_SBPI_CMD0_OFFSET		0x1000
 33#define OTPC_SBPI_CMD1_OFFSET		0x1004
 34
 35/* OTP Register bits and masks */
 36#define OTPC_USER_ADDR_MASK		GENMASK(31, 16)
 37#define OTPC_USE_USER			BIT(0)
 38#define OTPC_USE_USER_MASK		GENMASK(16, 16)
 39#define OTPC_USER_FSM_ENABLE		BIT(0)
 40#define OTPC_USER_FSM_ENABLE_MASK	GENMASK(16, 16)
 41#define OTPC_SBPI_DONE			BIT(1)
 42#define OTPC_USER_DONE			BIT(2)
 43
 44#define SBPI_DAP_ADDR			0x02
 45#define SBPI_DAP_ADDR_SHIFT		8
 46#define SBPI_DAP_ADDR_MASK		GENMASK(31, 24)
 47#define SBPI_CMD_VALID_MASK		GENMASK(31, 16)
 48#define SBPI_DAP_CMD_WRF		0xC0
 49#define SBPI_DAP_REG_ECC		0x3A
 50#define SBPI_ECC_ENABLE			0x00
 51#define SBPI_ECC_DISABLE		0x09
 52#define SBPI_ENABLE			BIT(0)
 53#define SBPI_ENABLE_MASK		GENMASK(16, 16)
 54
 55#define OTPC_TIMEOUT			10000
 56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 57struct rockchip_otp {
 58	struct device *dev;
 59	void __iomem *base;
 60	struct clk_bulk_data	*clks;
 61	int num_clks;
 62	struct reset_control *rst;
 63};
 64
 65/* list of required clocks */
 66static const char * const rockchip_otp_clocks[] = {
 67	"otp", "apb_pclk", "phy",
 68};
 69
 70struct rockchip_data {
 71	int size;
 72};
 73
 74static int rockchip_otp_reset(struct rockchip_otp *otp)
 75{
 76	int ret;
 77
 78	ret = reset_control_assert(otp->rst);
 79	if (ret) {
 80		dev_err(otp->dev, "failed to assert otp phy %d\n", ret);
 81		return ret;
 82	}
 83
 84	udelay(2);
 85
 86	ret = reset_control_deassert(otp->rst);
 87	if (ret) {
 88		dev_err(otp->dev, "failed to deassert otp phy %d\n", ret);
 89		return ret;
 90	}
 91
 92	return 0;
 93}
 94
 95static int rockchip_otp_wait_status(struct rockchip_otp *otp, u32 flag)
 
 96{
 97	u32 status = 0;
 98	int ret;
 99
100	ret = readl_poll_timeout_atomic(otp->base + OTPC_INT_STATUS, status,
101					(status & flag), 1, OTPC_TIMEOUT);
102	if (ret)
103		return ret;
104
105	/* clean int status */
106	writel(flag, otp->base + OTPC_INT_STATUS);
107
108	return 0;
109}
110
111static int rockchip_otp_ecc_enable(struct rockchip_otp *otp, bool enable)
112{
113	int ret = 0;
114
115	writel(SBPI_DAP_ADDR_MASK | (SBPI_DAP_ADDR << SBPI_DAP_ADDR_SHIFT),
116	       otp->base + OTPC_SBPI_CTRL);
117
118	writel(SBPI_CMD_VALID_MASK | 0x1, otp->base + OTPC_SBPI_CMD_VALID_PRE);
119	writel(SBPI_DAP_CMD_WRF | SBPI_DAP_REG_ECC,
120	       otp->base + OTPC_SBPI_CMD0_OFFSET);
121	if (enable)
122		writel(SBPI_ECC_ENABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
123	else
124		writel(SBPI_ECC_DISABLE, otp->base + OTPC_SBPI_CMD1_OFFSET);
125
126	writel(SBPI_ENABLE_MASK | SBPI_ENABLE, otp->base + OTPC_SBPI_CTRL);
127
128	ret = rockchip_otp_wait_status(otp, OTPC_SBPI_DONE);
129	if (ret < 0)
130		dev_err(otp->dev, "timeout during ecc_enable\n");
131
132	return ret;
133}
134
135static int rockchip_otp_read(void *context, unsigned int offset,
136			     void *val, size_t bytes)
137{
138	struct rockchip_otp *otp = context;
139	u8 *buf = val;
140	int ret = 0;
141
142	ret = clk_bulk_prepare_enable(otp->num_clks, otp->clks);
143	if (ret < 0) {
144		dev_err(otp->dev, "failed to prepare/enable clks\n");
145		return ret;
146	}
147
148	ret = rockchip_otp_reset(otp);
149	if (ret) {
150		dev_err(otp->dev, "failed to reset otp phy\n");
151		goto disable_clks;
152	}
153
154	ret = rockchip_otp_ecc_enable(otp, false);
155	if (ret < 0) {
156		dev_err(otp->dev, "rockchip_otp_ecc_enable err\n");
157		goto disable_clks;
158	}
159
160	writel(OTPC_USE_USER | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
161	udelay(5);
162	while (bytes--) {
163		writel(offset++ | OTPC_USER_ADDR_MASK,
164		       otp->base + OTPC_USER_ADDR);
165		writel(OTPC_USER_FSM_ENABLE | OTPC_USER_FSM_ENABLE_MASK,
166		       otp->base + OTPC_USER_ENABLE);
167		ret = rockchip_otp_wait_status(otp, OTPC_USER_DONE);
168		if (ret < 0) {
169			dev_err(otp->dev, "timeout during read setup\n");
170			goto read_end;
171		}
172		*buf++ = readb(otp->base + OTPC_USER_Q);
173	}
174
175read_end:
176	writel(0x0 | OTPC_USE_USER_MASK, otp->base + OTPC_USER_CTRL);
177disable_clks:
178	clk_bulk_disable_unprepare(otp->num_clks, otp->clks);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
179
180	return ret;
181}
182
183static struct nvmem_config otp_config = {
184	.name = "rockchip-otp",
185	.owner = THIS_MODULE,
 
 
186	.read_only = true,
187	.stride = 1,
188	.word_size = 1,
189	.reg_read = rockchip_otp_read,
190};
191
 
 
 
 
192static const struct rockchip_data px30_data = {
193	.size = 0x40,
 
 
 
 
 
 
 
 
 
 
 
 
 
 
194};
195
196static const struct of_device_id rockchip_otp_match[] = {
197	{
198		.compatible = "rockchip,px30-otp",
199		.data = (void *)&px30_data,
200	},
201	{
202		.compatible = "rockchip,rk3308-otp",
203		.data = (void *)&px30_data,
 
 
 
 
204	},
205	{ /* sentinel */ },
206};
207MODULE_DEVICE_TABLE(of, rockchip_otp_match);
208
209static int rockchip_otp_probe(struct platform_device *pdev)
210{
211	struct device *dev = &pdev->dev;
212	struct rockchip_otp *otp;
213	const struct rockchip_data *data;
214	struct nvmem_device *nvmem;
215	int ret, i;
216
217	data = of_device_get_match_data(dev);
218	if (!data) {
219		dev_err(dev, "failed to get match data\n");
220		return -EINVAL;
221	}
222
223	otp = devm_kzalloc(&pdev->dev, sizeof(struct rockchip_otp),
224			   GFP_KERNEL);
225	if (!otp)
226		return -ENOMEM;
227
 
228	otp->dev = dev;
229	otp->base = devm_platform_ioremap_resource(pdev, 0);
230	if (IS_ERR(otp->base))
231		return PTR_ERR(otp->base);
 
232
233	otp->num_clks = ARRAY_SIZE(rockchip_otp_clocks);
234	otp->clks = devm_kcalloc(dev, otp->num_clks,
235				     sizeof(*otp->clks), GFP_KERNEL);
236	if (!otp->clks)
237		return -ENOMEM;
238
239	for (i = 0; i < otp->num_clks; ++i)
240		otp->clks[i].id = rockchip_otp_clocks[i];
241
242	ret = devm_clk_bulk_get(dev, otp->num_clks, otp->clks);
243	if (ret)
244		return ret;
245
246	otp->rst = devm_reset_control_get(dev, "phy");
247	if (IS_ERR(otp->rst))
248		return PTR_ERR(otp->rst);
 
249
250	otp_config.size = data->size;
251	otp_config.priv = otp;
252	otp_config.dev = dev;
 
253	nvmem = devm_nvmem_register(dev, &otp_config);
254
255	return PTR_ERR_OR_ZERO(nvmem);
 
 
256}
257
258static struct platform_driver rockchip_otp_driver = {
259	.probe = rockchip_otp_probe,
260	.driver = {
261		.name = "rockchip-otp",
262		.of_match_table = rockchip_otp_match,
263	},
264};
265
266module_platform_driver(rockchip_otp_driver);
267MODULE_DESCRIPTION("Rockchip OTP driver");
268MODULE_LICENSE("GPL v2");