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