brintos

brintos / linux-shallow public Read only

0
0
Text · 8.8 KiB · ebc3f0b Raw
368 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Rockchip OTP Driver4 *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			0x002024#define OTPC_SBPI_CMD_VALID_PRE		0x002425#define OTPC_SBPI_CS_VALID_PRE		0x002826#define OTPC_SBPI_STATUS		0x002C27#define OTPC_USER_CTRL			0x010028#define OTPC_USER_ADDR			0x010429#define OTPC_USER_ENABLE		0x010830#define OTPC_USER_Q			0x012431#define OTPC_INT_STATUS			0x030432#define OTPC_SBPI_CMD0_OFFSET		0x100033#define OTPC_SBPI_CMD1_OFFSET		0x100434 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			0x0245#define SBPI_DAP_ADDR_SHIFT		846#define SBPI_DAP_ADDR_MASK		GENMASK(31, 24)47#define SBPI_CMD_VALID_MASK		GENMASK(31, 16)48#define SBPI_DAP_CMD_WRF		0xC049#define SBPI_DAP_REG_ECC		0x3A50#define SBPI_ECC_ENABLE			0x0051#define SBPI_ECC_DISABLE		0x0952#define SBPI_ENABLE			BIT(0)53#define SBPI_ENABLE_MASK		GENMASK(16, 16)54 55#define OTPC_TIMEOUT			1000056 57/* RK3588 Register */58#define RK3588_OTPC_AUTO_CTRL		0x0459#define RK3588_OTPC_AUTO_EN		0x0860#define RK3588_OTPC_INT_ST		0x8461#define RK3588_OTPC_DOUT0		0x2062#define RK3588_NO_SECURE_OFFSET		0x30063#define RK3588_NBYTES			464#define RK3588_BURST_NUM		165#define RK3588_BURST_SHIFT		866#define RK3588_ADDR_SHIFT		1667#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	else136		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");368