1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Texas Instruments' K3 Error Signalling Module driver
4  *
5  * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
6  *      Tero Kristo <t-kristo@ti.com>
7  *
8  */
9 
10 #include <common.h>
11 #include <dm.h>
12 #include <errno.h>
13 #include <asm/io.h>
14 #include <dm/device_compat.h>
15 #include <linux/bitops.h>
16 
17 #define ESM_SFT_RST			0x0c
18 #define ESM_SFT_RST_KEY			0x0f
19 #define ESM_EN				0x08
20 #define ESM_EN_KEY			0x0f
21 
22 #define ESM_STS(i)			(0x404 + (i) / 32 * 0x20)
23 #define ESM_STS_MASK(i)			(1 << ((i) % 32))
24 #define ESM_PIN_EN_SET_OFFSET(i)	(0x414 + (i) / 32 * 0x20)
25 #define ESM_PIN_MASK(i)			(1 << ((i) % 32))
26 #define ESM_INTR_EN_SET_OFFSET(i)	(0x408 + (i) / 32 * 0x20)
27 #define ESM_INTR_MASK(i)		(1 << ((i) % 32))
28 #define ESM_INTR_PRIO_SET_OFFSET(i)	(0x410 + (i) / 32 * 0x20)
29 #define ESM_INTR_PRIO_MASK(i)		(1 << ((i) % 32))
30 
esm_pin_enable(void __iomem * base,int pin)31 static void esm_pin_enable(void __iomem *base, int pin)
32 {
33 	u32 value;
34 
35 	value = readl(base + ESM_PIN_EN_SET_OFFSET(pin));
36 	value |= ESM_PIN_MASK(pin);
37 	/* Enable event */
38 	writel(value, base + ESM_PIN_EN_SET_OFFSET(pin));
39 }
40 
esm_intr_enable(void __iomem * base,int pin)41 static void esm_intr_enable(void __iomem *base, int pin)
42 {
43 	u32 value;
44 
45 	value = readl(base + ESM_INTR_EN_SET_OFFSET(pin));
46 	value |= ESM_INTR_MASK(pin);
47 	/* Enable Interrupt event */
48 	writel(value, base + ESM_INTR_EN_SET_OFFSET(pin));
49 }
50 
esm_intr_prio_set(void __iomem * base,int pin)51 static void esm_intr_prio_set(void __iomem *base, int pin)
52 {
53 	u32 value;
54 
55 	value = readl(base + ESM_INTR_PRIO_SET_OFFSET(pin));
56 	value |= ESM_INTR_PRIO_MASK(pin);
57 	/* Set to priority */
58 	writel(value, base + ESM_INTR_PRIO_SET_OFFSET(pin));
59 }
60 
esm_clear_raw_status(void __iomem * base,int pin)61 static void esm_clear_raw_status(void __iomem *base, int pin)
62 {
63 	u32 value;
64 
65 	value = readl(base + ESM_STS(pin));
66 	value |= ESM_STS_MASK(pin);
67 	/* Clear Event status */
68 	writel(value, base + ESM_STS(pin));
69 }
70 /**
71  * k3_esm_probe: configures ESM based on DT data
72  *
73  * Parses ESM info from device tree, and configures the module accordingly.
74  */
k3_esm_probe(struct udevice * dev)75 static int k3_esm_probe(struct udevice *dev)
76 {
77 	int ret;
78 	void __iomem *base;
79 	int num_pins;
80 	u32 *pins;
81 	int i;
82 
83 	base = dev_remap_addr_index(dev, 0);
84 	if (!base)
85 		return -ENODEV;
86 
87 	num_pins = dev_read_size(dev, "ti,esm-pins");
88 	if (num_pins < 0) {
89 		dev_err(dev, "ti,esm-pins property missing or invalid: %d\n",
90 			num_pins);
91 		return num_pins;
92 	}
93 
94 	num_pins /= sizeof(u32);
95 
96 	pins = kmalloc(num_pins * sizeof(u32), __GFP_ZERO);
97 	if (!pins)
98 		return -ENOMEM;
99 
100 	ret = dev_read_u32_array(dev, "ti,esm-pins", pins, num_pins);
101 	if (ret < 0) {
102 		dev_err(dev, "failed to read ti,esm-pins property: %d\n",
103 			ret);
104 		goto free_pins;
105 	}
106 
107 	/* Clear any pending events */
108 	writel(ESM_SFT_RST_KEY, base + ESM_SFT_RST);
109 
110 	for (i = 0; i < num_pins; i++) {
111 		esm_intr_prio_set(base, pins[i]);
112 		esm_clear_raw_status(base, pins[i]);
113 		esm_pin_enable(base, pins[i]);
114 		esm_intr_enable(base, pins[i]);
115 	}
116 
117 	/* Enable ESM */
118 	writel(ESM_EN_KEY, base + ESM_EN);
119 
120 free_pins:
121 	kfree(pins);
122 	return ret;
123 }
124 
125 static const struct udevice_id k3_esm_ids[] = {
126 	{ .compatible = "ti,j721e-esm" },
127 	{}
128 };
129 
130 U_BOOT_DRIVER(k3_esm) = {
131 	.name = "k3_esm",
132 	.of_match = k3_esm_ids,
133 	.id = UCLASS_MISC,
134 	.probe = k3_esm_probe,
135 };
136