summaryrefslogtreecommitdiff
path: root/drivers/misc/k3_esm.c
blob: 41faeb3d858201f521ee7416a359e260a048cec6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// SPDX-License-Identifier: GPL-2.0+
/*
 * Texas Instruments' K3 Error Signalling Module driver
 *
 * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/
 *      Tero Kristo <t-kristo@ti.com>
 *
 */

#include <common.h>
#include <dm.h>
#include <errno.h>
#include <asm/io.h>
#include <dm/device_compat.h>
#include <linux/bitops.h>

#define ESM_SFT_RST			0x0c
#define ESM_SFT_RST_KEY			0x0f
#define ESM_EN				0x08
#define ESM_EN_KEY			0x0f

#define ESM_STS(i)			(0x404 + (i) / 32 * 0x20)
#define ESM_STS_MASK(i)			(1 << ((i) % 32))
#define ESM_PIN_EN_SET_OFFSET(i)	(0x414 + (i) / 32 * 0x20)
#define ESM_PIN_MASK(i)			(1 << ((i) % 32))
#define ESM_INTR_EN_SET_OFFSET(i)	(0x408 + (i) / 32 * 0x20)
#define ESM_INTR_MASK(i)		(1 << ((i) % 32))
#define ESM_INTR_PRIO_SET_OFFSET(i)	(0x410 + (i) / 32 * 0x20)
#define ESM_INTR_PRIO_MASK(i)		(1 << ((i) % 32))

static void esm_pin_enable(void __iomem *base, int pin)
{
	u32 value;

	value = readl(base + ESM_PIN_EN_SET_OFFSET(pin));
	value |= ESM_PIN_MASK(pin);
	/* Enable event */
	writel(value, base + ESM_PIN_EN_SET_OFFSET(pin));
}

static void esm_intr_enable(void __iomem *base, int pin)
{
	u32 value;

	value = readl(base + ESM_INTR_EN_SET_OFFSET(pin));
	value |= ESM_INTR_MASK(pin);
	/* Enable Interrupt event */
	writel(value, base + ESM_INTR_EN_SET_OFFSET(pin));
}

static void esm_intr_prio_set(void __iomem *base, int pin)
{
	u32 value;

	value = readl(base + ESM_INTR_PRIO_SET_OFFSET(pin));
	value |= ESM_INTR_PRIO_MASK(pin);
	/* Set to priority */
	writel(value, base + ESM_INTR_PRIO_SET_OFFSET(pin));
}

static void esm_clear_raw_status(void __iomem *base, int pin)
{
	u32 value;

	value = readl(base + ESM_STS(pin));
	value |= ESM_STS_MASK(pin);
	/* Clear Event status */
	writel(value, base + ESM_STS(pin));
}
/**
 * k3_esm_probe: configures ESM based on DT data
 *
 * Parses ESM info from device tree, and configures the module accordingly.
 */
static int k3_esm_probe(struct udevice *dev)
{
	int ret;
	void __iomem *base;
	int num_pins;
	u32 *pins;
	int i;

	base = dev_remap_addr_index(dev, 0);
	if (!base)
		return -ENODEV;

	num_pins = dev_read_size(dev, "ti,esm-pins");
	if (num_pins < 0) {
		dev_err(dev, "ti,esm-pins property missing or invalid: %d\n",
			num_pins);
		return num_pins;
	}

	num_pins /= sizeof(u32);

	pins = kmalloc(num_pins * sizeof(u32), __GFP_ZERO);
	if (!pins)
		return -ENOMEM;

	ret = dev_read_u32_array(dev, "ti,esm-pins", pins, num_pins);
	if (ret < 0) {
		dev_err(dev, "failed to read ti,esm-pins property: %d\n",
			ret);
		goto free_pins;
	}

	/* Clear any pending events */
	writel(ESM_SFT_RST_KEY, base + ESM_SFT_RST);

	for (i = 0; i < num_pins; i++) {
		esm_intr_prio_set(base, pins[i]);
		esm_clear_raw_status(base, pins[i]);
		esm_pin_enable(base, pins[i]);
		esm_intr_enable(base, pins[i]);
	}

	/* Enable ESM */
	writel(ESM_EN_KEY, base + ESM_EN);

free_pins:
	kfree(pins);
	return ret;
}

static const struct udevice_id k3_esm_ids[] = {
	{ .compatible = "ti,j721e-esm" },
	{}
};

U_BOOT_DRIVER(k3_esm) = {
	.name = "k3_esm",
	.of_match = k3_esm_ids,
	.id = UCLASS_MISC,
	.probe = k3_esm_probe,
};