blob: fd2988e91b5a9ca2d0f846b557e76379bd410ca3 [file] [log] [blame]
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +01001// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright 2020, Heinrich Schuchardt <xypron.glpk@gmx.de>
4 *
5 * Driver for Amlogic hardware random number generator
6 */
7
8#include <common.h>
9#include <clk.h>
10#include <dm.h>
11#include <rng.h>
12#include <asm/io.h>
Alexey Romanova9234562023-10-12 10:58:25 +030013#include <linux/iopoll.h>
14
15#define RNG_DATA 0x00
16#define RNG_S4_DATA 0x08
17#define RNG_S4_CFG 0x00
18
19#define RUN_BIT BIT(0)
20#define SEED_READY_STS_BIT BIT(31)
21
22struct meson_rng_priv {
23 u32 (*read)(fdt_addr_t base);
24};
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +010025
Simon Glass8a8d24b2020-12-03 16:55:23 -070026struct meson_rng_plat {
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +010027 fdt_addr_t base;
28 struct clk clk;
Alexey Romanova9234562023-10-12 10:58:25 +030029 struct meson_rng_priv *priv;
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +010030};
31
32/**
33 * meson_rng_read() - fill buffer with random bytes
34 *
35 * @buffer: buffer to receive data
36 * @size: size of buffer
37 *
38 * Return: 0
39 */
40static int meson_rng_read(struct udevice *dev, void *data, size_t len)
41{
Simon Glass8a8d24b2020-12-03 16:55:23 -070042 struct meson_rng_plat *pdata = dev_get_plat(dev);
Alexey Romanova9234562023-10-12 10:58:25 +030043 struct meson_rng_priv *priv = pdata->priv;
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +010044 char *buffer = (char *)data;
45
46 while (len) {
Alexey Romanova9234562023-10-12 10:58:25 +030047 u32 rand = priv->read(pdata->base);
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +010048 size_t step;
49
50 if (len >= 4)
51 step = 4;
52 else
53 step = len;
54 memcpy(buffer, &rand, step);
55 buffer += step;
56 len -= step;
57 }
58 return 0;
59}
60
Alexey Romanova9234562023-10-12 10:58:25 +030061static int meson_rng_wait_status(void __iomem *cfg_addr, int bit)
62{
63 u32 status = 0;
64 int ret;
65
66 ret = readl_relaxed_poll_timeout(cfg_addr,
67 status, !(status & bit),
68 10000);
69 if (ret)
70 return -EBUSY;
71
72 return 0;
73}
74
75static u32 meson_common_rng_read(fdt_addr_t base)
76{
77 return readl(base);
78}
79
80static u32 meson_s4_rng_read(fdt_addr_t base)
81{
82 void __iomem *cfg_addr = (void *)base + RNG_S4_CFG;
83 int err;
84
85 writel_relaxed(readl_relaxed(cfg_addr) | SEED_READY_STS_BIT, cfg_addr);
86
87 err = meson_rng_wait_status(cfg_addr, SEED_READY_STS_BIT);
88 if (err) {
89 pr_err("Seed isn't ready, try again\n");
90 return err;
91 }
92
93 err = meson_rng_wait_status(cfg_addr, RUN_BIT);
94 if (err) {
95 pr_err("Can't get random number, try again\n");
96 return err;
97 }
98
99 return readl_relaxed(base + RNG_S4_DATA);
100}
101
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100102/**
103 * meson_rng_probe() - probe rng device
104 *
105 * @dev: device
106 * Return: 0 if ok
107 */
108static int meson_rng_probe(struct udevice *dev)
109{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700110 struct meson_rng_plat *pdata = dev_get_plat(dev);
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100111 int err;
112
113 err = clk_enable(&pdata->clk);
114 if (err)
115 return err;
116
Alexey Romanova9234562023-10-12 10:58:25 +0300117 pdata->priv = (struct meson_rng_priv *)dev_get_driver_data(dev);
118
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100119 return 0;
120}
121
122/**
123 * meson_rng_remove() - deinitialize rng device
124 *
125 * @dev: device
126 * Return: 0 if ok
127 */
128static int meson_rng_remove(struct udevice *dev)
129{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700130 struct meson_rng_plat *pdata = dev_get_plat(dev);
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100131
132 return clk_disable(&pdata->clk);
133}
134
135/**
Simon Glassd1998a92020-12-03 16:55:21 -0700136 * meson_rng_of_to_plat() - transfer device tree data to plaform data
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100137 *
138 * @dev: device
139 * Return: 0 if ok
140 */
Simon Glassd1998a92020-12-03 16:55:21 -0700141static int meson_rng_of_to_plat(struct udevice *dev)
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100142{
Simon Glass8a8d24b2020-12-03 16:55:23 -0700143 struct meson_rng_plat *pdata = dev_get_plat(dev);
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100144 int err;
145
146 pdata->base = dev_read_addr(dev);
147 if (!pdata->base)
148 return -ENODEV;
149
Neil Armstrong02d249f2020-09-25 09:19:20 +0200150 /* Get optional "core" clock */
Sean Andersone96e2132022-01-15 15:52:47 -0500151 err = clk_get_by_name_optional(dev, "core", &pdata->clk);
152 if (err)
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100153 return err;
154
155 return 0;
156}
157
158static const struct dm_rng_ops meson_rng_ops = {
159 .read = meson_rng_read,
160};
161
Alexey Romanova9234562023-10-12 10:58:25 +0300162static const struct meson_rng_priv meson_rng_priv = {
163 .read = meson_common_rng_read,
164};
165
166static const struct meson_rng_priv meson_rng_priv_s4 = {
167 .read = meson_s4_rng_read,
168};
169
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100170static const struct udevice_id meson_rng_match[] = {
171 {
172 .compatible = "amlogic,meson-rng",
Alexey Romanova9234562023-10-12 10:58:25 +0300173 .data = (ulong)&meson_rng_priv,
174 },
175 {
176 .compatible = "amlogic,meson-s4-rng",
177 .data = (ulong)&meson_rng_priv_s4,
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100178 },
179 {},
180};
181
182U_BOOT_DRIVER(meson_rng) = {
183 .name = "meson-rng",
184 .id = UCLASS_RNG,
185 .of_match = meson_rng_match,
186 .ops = &meson_rng_ops,
187 .probe = meson_rng_probe,
188 .remove = meson_rng_remove,
Simon Glass8a8d24b2020-12-03 16:55:23 -0700189 .plat_auto = sizeof(struct meson_rng_plat),
Simon Glassd1998a92020-12-03 16:55:21 -0700190 .of_to_plat = meson_rng_of_to_plat,
Heinrich Schuchardtbc40eb22020-02-02 19:52:04 +0100191};