summaryrefslogtreecommitdiff
path: root/drivers/misc/npcm_host_intf.c
blob: e3b0663625b0d0879f495915ed4dea55cf18302d (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
136
137
138
139
140
// SPDX-License-Identifier: GPL-2.0+
/*
 * Host interface (LPC or eSPI) configuration on Nuvoton BMC
 * Copyright (c) 2022 Nuvoton Technology Corp.
 */

#include <dm.h>
#include <regmap.h>
#include <syscon.h>
#include <asm/io.h>
#include <dm/device_compat.h>
#include <linux/bitfield.h>

#define SMC_CTL_REG_ADDR	0xc0001001
#define SMC_CTL_HOSTWAIT	0x80

/* GCR Register Offsets */
#define HIFCR			0x50
#define MFSEL1			0x260
#define MFSEL4			0x26c

/* ESPI Register offsets */
#define ESPICFG			0x4
#define ESPIHINDP		0x80
#define ESPI_TEN		0xF0
#define ESPI_ENG		0xF1

/* MFSEL bit fileds */
#define MFSEL1_LPCSEL		BIT(26)
#define MFSEL4_ESPISEL		BIT(8)

/* ESPICFG bit fileds */
#define CHSUPP_MASK		GENMASK(27, 24)
#define IOMODE_MASK		GENMASK(9, 8)
#define IOMODE_SDQ		FIELD_PREP(IOMODE_MASK, 3)
#define MAXFREQ_MASK		GENMASK(12, 10)
#define MAXFREQ_33MHZ		FIELD_PREP(MAXFREQ_MASK, 2)

/* ESPIHINDP bit fileds */
#define AUTO_SBLD		BIT(4)
#define AUTO_HS1		BIT(8)
#define AUTO_HS2		BIT(12)
#define AUTO_HS3		BIT(16)

#define ESPI_TEN_ENABLE		0x55
#define ESPI_TEN_DISABLE	0

/* KCS/BPC interrupt control */
#define BPCFEN			0x46
#define FRIE			BIT(3)
#define HRIE			BIT(4)
#define KCS1CTL			0x18
#define KCS2CTL			0x2a
#define KCS3CTL			0x3c
#define IBFIE			BIT(0)
#define OBEIE			BIT(1)

static int npcm_host_intf_bind(struct udevice *dev)
{
	struct regmap *syscon;
	void __iomem *base, *kcs_base;
	u32 ch_supp, val;
	u32 ioaddr;
	const char *type;
	int ret;

	syscon = syscon_regmap_lookup_by_phandle(dev, "syscon");
	if (IS_ERR(syscon)) {
		dev_err(dev, "%s: unable to get syscon, dev %s\n", __func__, dev->name);
		return PTR_ERR(syscon);
	}

	ioaddr  = dev_read_u32_default(dev, "ioaddr", 0);
	if (ioaddr)
		regmap_write(syscon, HIFCR, ioaddr);

	type = dev_read_string(dev, "type");
	if (!type)
		return -EINVAL;

	if (!strcmp(type, "espi")) {
		base = dev_read_addr_ptr(dev);
		if (!base)
			return -EINVAL;

		ret = dev_read_u32(dev, "channel-support", &ch_supp);
		if (ret)
			return ret;

		/* Select eSPI pins function */
		regmap_update_bits(syscon, MFSEL1, MFSEL1_LPCSEL, 0);
		regmap_update_bits(syscon, MFSEL4, MFSEL4_ESPISEL, MFSEL4_ESPISEL);

		val = AUTO_SBLD | AUTO_HS1 | AUTO_HS2 | AUTO_HS3 | ch_supp;
		writel(val, base + ESPIHINDP);

		val = readl(base + ESPICFG);
		val &= ~(CHSUPP_MASK | IOMODE_MASK | MAXFREQ_MASK);
		val |= IOMODE_SDQ | MAXFREQ_33MHZ | FIELD_PREP(CHSUPP_MASK, ch_supp);
		writel(val, base + ESPICFG);

		if (device_is_compatible(dev, "nuvoton,npcm845-host-intf")) {
			/* Workaround: avoid eSPI module getting into wrong state */
			writeb(ESPI_TEN_ENABLE, base + ESPI_TEN);
			writeb(BIT(6), base + ESPI_ENG);
			writeb(ESPI_TEN_DISABLE, base + ESPI_TEN);
		}
	} else if (!strcmp(type, "lpc")) {
		/* Select LPC pin function */
		regmap_update_bits(syscon, MFSEL4, MFSEL4_ESPISEL, 0);
		regmap_update_bits(syscon, MFSEL1, MFSEL1_LPCSEL, MFSEL1_LPCSEL);
	}

	/* Release host wait */
	setbits_8(SMC_CTL_REG_ADDR, SMC_CTL_HOSTWAIT);

	kcs_base = dev_read_addr_index_ptr(dev, 1);
	if (kcs_base) {
		/* Disable KCS/BPC interrupts */
		clrbits_8(kcs_base + BPCFEN, FRIE | HRIE);
		clrbits_8(kcs_base + KCS1CTL, IBFIE | OBEIE);
		clrbits_8(kcs_base + KCS2CTL, IBFIE | OBEIE);
		clrbits_8(kcs_base + KCS3CTL, IBFIE | OBEIE);
	}

	return 0;
}

static const struct udevice_id npcm_hostintf_ids[] = {
	{ .compatible = "nuvoton,npcm750-host-intf" },
	{ .compatible = "nuvoton,npcm845-host-intf" },
	{ }
};

U_BOOT_DRIVER(npcm_host_intf) = {
	.name	= "npcm_host_intf",
	.id	= UCLASS_MISC,
	.of_match = npcm_hostintf_ids,
	.bind = npcm_host_intf_bind,
};