1 // SPDX-License-Identifier: GPL-2.0 2 /* Copyright (C) 2024 Christian Marangi */ 3 4 #include <linux/kernel.h> 5 #include <linux/module.h> 6 #include <linux/mod_devicetable.h> 7 #include <linux/bitfield.h> 8 #include <linux/delay.h> 9 #include <linux/hw_random.h> 10 #include <linux/interrupt.h> 11 #include <linux/io.h> 12 #include <linux/iopoll.h> 13 #include <linux/platform_device.h> 14 15 #define TRNG_IP_RDY 0x800 16 #define CNT_TRANS GENMASK(15, 8) 17 #define SAMPLE_RDY BIT(0) 18 #define TRNG_NS_SEK_AND_DAT_EN 0x804 19 #define RNG_EN BIT(31) /* referenced as ring_en */ 20 #define RAW_DATA_EN BIT(16) 21 #define TRNG_HEALTH_TEST_SW_RST 0x808 22 #define SW_RST BIT(0) /* Active High */ 23 #define TRNG_INTR_EN 0x818 24 #define INTR_MASK BIT(16) 25 #define CONTINUOUS_HEALTH_INITR_EN BIT(2) 26 #define SW_STARTUP_INITR_EN BIT(1) 27 #define RST_STARTUP_INITR_EN BIT(0) 28 /* Notice that Health Test are done only out of Reset and with RNG_EN */ 29 #define TRNG_HEALTH_TEST_STATUS 0x824 30 #define CONTINUOUS_HEALTH_AP_TEST_FAIL BIT(23) 31 #define CONTINUOUS_HEALTH_RC_TEST_FAIL BIT(22) 32 #define SW_STARTUP_TEST_DONE BIT(21) 33 #define SW_STARTUP_AP_TEST_FAIL BIT(20) 34 #define SW_STARTUP_RC_TEST_FAIL BIT(19) 35 #define RST_STARTUP_TEST_DONE BIT(18) 36 #define RST_STARTUP_AP_TEST_FAIL BIT(17) 37 #define RST_STARTUP_RC_TEST_FAIL BIT(16) 38 #define RAW_DATA_VALID BIT(7) 39 40 #define TRNG_RAW_DATA_OUT 0x828 41 42 #define TRNG_CNT_TRANS_VALID 0x80 43 #define BUSY_LOOP_SLEEP 10 44 #define BUSY_LOOP_TIMEOUT (BUSY_LOOP_SLEEP * 10000) 45 46 struct airoha_trng { 47 void __iomem *base; 48 struct hwrng rng; 49 struct device *dev; 50 51 struct completion rng_op_done; 52 }; 53 54 static int airoha_trng_irq_mask(struct airoha_trng *trng) 55 { 56 u32 val; 57 58 val = readl(trng->base + TRNG_INTR_EN); 59 val |= INTR_MASK; 60 writel(val, trng->base + TRNG_INTR_EN); 61 62 return 0; 63 } 64 65 static int airoha_trng_irq_unmask(struct airoha_trng *trng) 66 { 67 u32 val; 68 69 val = readl(trng->base + TRNG_INTR_EN); 70 val &= ~INTR_MASK; 71 writel(val, trng->base + TRNG_INTR_EN); 72 73 return 0; 74 } 75 76 static int airoha_trng_init(struct hwrng *rng) 77 { 78 struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); 79 int ret; 80 u32 val; 81 82 val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); 83 val |= RNG_EN; 84 writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); 85 86 /* Set out of SW Reset */ 87 airoha_trng_irq_unmask(trng); 88 writel(0, trng->base + TRNG_HEALTH_TEST_SW_RST); 89 90 ret = wait_for_completion_timeout(&trng->rng_op_done, BUSY_LOOP_TIMEOUT); 91 if (ret <= 0) { 92 dev_err(trng->dev, "Timeout waiting for Health Check\n"); 93 airoha_trng_irq_mask(trng); 94 return -ENODEV; 95 } 96 97 /* Check if Health Test Failed */ 98 val = readl(trng->base + TRNG_HEALTH_TEST_STATUS); 99 if (val & (RST_STARTUP_AP_TEST_FAIL | RST_STARTUP_RC_TEST_FAIL)) { 100 dev_err(trng->dev, "Health Check fail: %s test fail\n", 101 val & RST_STARTUP_AP_TEST_FAIL ? "AP" : "RC"); 102 return -ENODEV; 103 } 104 105 /* Check if IP is ready */ 106 ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val, 107 val & SAMPLE_RDY, 10, 1000); 108 if (ret < 0) { 109 dev_err(trng->dev, "Timeout waiting for IP ready"); 110 return -ENODEV; 111 } 112 113 /* CNT_TRANS must be 0x80 for IP to be considered ready */ 114 ret = readl_poll_timeout(trng->base + TRNG_IP_RDY, val, 115 FIELD_GET(CNT_TRANS, val) == TRNG_CNT_TRANS_VALID, 116 10, 1000); 117 if (ret < 0) { 118 dev_err(trng->dev, "Timeout waiting for IP ready"); 119 return -ENODEV; 120 } 121 122 return 0; 123 } 124 125 static void airoha_trng_cleanup(struct hwrng *rng) 126 { 127 struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); 128 u32 val; 129 130 val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); 131 val &= ~RNG_EN; 132 writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); 133 134 /* Put it in SW Reset */ 135 writel(SW_RST, trng->base + TRNG_HEALTH_TEST_SW_RST); 136 } 137 138 static int airoha_trng_read(struct hwrng *rng, void *buf, size_t max, bool wait) 139 { 140 struct airoha_trng *trng = container_of(rng, struct airoha_trng, rng); 141 u32 *data = buf; 142 u32 status; 143 int ret; 144 145 ret = readl_poll_timeout(trng->base + TRNG_HEALTH_TEST_STATUS, status, 146 status & RAW_DATA_VALID, 10, 1000); 147 if (ret < 0) { 148 dev_err(trng->dev, "Timeout waiting for TRNG RAW Data valid\n"); 149 return ret; 150 } 151 152 *data = readl(trng->base + TRNG_RAW_DATA_OUT); 153 154 return 4; 155 } 156 157 static irqreturn_t airoha_trng_irq(int irq, void *priv) 158 { 159 struct airoha_trng *trng = (struct airoha_trng *)priv; 160 161 airoha_trng_irq_mask(trng); 162 /* Just complete the task, we will read the value later */ 163 complete(&trng->rng_op_done); 164 165 return IRQ_HANDLED; 166 } 167 168 static int airoha_trng_probe(struct platform_device *pdev) 169 { 170 struct device *dev = &pdev->dev; 171 struct airoha_trng *trng; 172 int irq, ret; 173 u32 val; 174 175 trng = devm_kzalloc(dev, sizeof(*trng), GFP_KERNEL); 176 if (!trng) 177 return -ENOMEM; 178 179 trng->base = devm_platform_ioremap_resource(pdev, 0); 180 if (IS_ERR(trng->base)) 181 return PTR_ERR(trng->base); 182 183 irq = platform_get_irq(pdev, 0); 184 if (irq < 0) 185 return irq; 186 187 airoha_trng_irq_mask(trng); 188 ret = devm_request_irq(&pdev->dev, irq, airoha_trng_irq, 0, 189 pdev->name, (void *)trng); 190 if (ret) { 191 dev_err(dev, "Can't get interrupt working.\n"); 192 return ret; 193 } 194 195 init_completion(&trng->rng_op_done); 196 197 /* Enable interrupt for SW reset Health Check */ 198 val = readl(trng->base + TRNG_INTR_EN); 199 val |= RST_STARTUP_INITR_EN; 200 writel(val, trng->base + TRNG_INTR_EN); 201 202 /* Set output to raw data */ 203 val = readl(trng->base + TRNG_NS_SEK_AND_DAT_EN); 204 val |= RAW_DATA_EN; 205 writel(val, trng->base + TRNG_NS_SEK_AND_DAT_EN); 206 207 /* Put it in SW Reset */ 208 writel(SW_RST, trng->base + TRNG_HEALTH_TEST_SW_RST); 209 210 trng->dev = dev; 211 trng->rng.name = pdev->name; 212 trng->rng.init = airoha_trng_init; 213 trng->rng.cleanup = airoha_trng_cleanup; 214 trng->rng.read = airoha_trng_read; 215 216 ret = devm_hwrng_register(dev, &trng->rng); 217 if (ret) { 218 dev_err(dev, "failed to register rng device: %d\n", ret); 219 return ret; 220 } 221 222 return 0; 223 } 224 225 static const struct of_device_id airoha_trng_of_match[] = { 226 { .compatible = "airoha,en7581-trng", }, 227 {}, 228 }; 229 MODULE_DEVICE_TABLE(of, airoha_trng_of_match); 230 231 static struct platform_driver airoha_trng_driver = { 232 .driver = { 233 .name = "airoha-trng", 234 .of_match_table = airoha_trng_of_match, 235 }, 236 .probe = airoha_trng_probe, 237 }; 238 239 module_platform_driver(airoha_trng_driver); 240 241 MODULE_LICENSE("GPL"); 242 MODULE_AUTHOR("Christian Marangi <ansuelsmth@gmail.com>"); 243 MODULE_DESCRIPTION("Airoha True Random Number Generator driver"); 244